aboutsummaryrefslogtreecommitdiffstats
path: root/LibOVR/Src
diff options
context:
space:
mode:
Diffstat (limited to 'LibOVR/Src')
-rw-r--r--LibOVR/Src/Kernel/OVR_Alg.cpp92
-rw-r--r--LibOVR/Src/Kernel/OVR_Alg.h1906
-rw-r--r--LibOVR/Src/Kernel/OVR_Allocator.cpp168
-rw-r--r--LibOVR/Src/Kernel/OVR_Allocator.h672
-rw-r--r--LibOVR/Src/Kernel/OVR_Array.h1586
-rw-r--r--LibOVR/Src/Kernel/OVR_Atomic.cpp164
-rw-r--r--LibOVR/Src/Kernel/OVR_Atomic.h1718
-rw-r--r--LibOVR/Src/Kernel/OVR_Color.h110
-rw-r--r--LibOVR/Src/Kernel/OVR_ContainerAllocator.h512
-rw-r--r--LibOVR/Src/Kernel/OVR_File.cpp1142
-rw-r--r--LibOVR/Src/Kernel/OVR_File.h1036
-rw-r--r--LibOVR/Src/Kernel/OVR_FileFILE.cpp1166
-rw-r--r--LibOVR/Src/Kernel/OVR_Hash.h2582
-rw-r--r--LibOVR/Src/Kernel/OVR_KeyCodes.h480
-rw-r--r--LibOVR/Src/Kernel/OVR_List.h650
-rw-r--r--LibOVR/Src/Kernel/OVR_Log.cpp346
-rw-r--r--LibOVR/Src/Kernel/OVR_Log.h386
-rw-r--r--LibOVR/Src/Kernel/OVR_Math.cpp306
-rw-r--r--LibOVR/Src/Kernel/OVR_Math.h2219
-rw-r--r--LibOVR/Src/Kernel/OVR_RefCount.cpp200
-rw-r--r--LibOVR/Src/Kernel/OVR_RefCount.h1044
-rw-r--r--LibOVR/Src/Kernel/OVR_Std.cpp2050
-rw-r--r--LibOVR/Src/Kernel/OVR_Std.h1006
-rw-r--r--LibOVR/Src/Kernel/OVR_String.cpp1504
-rw-r--r--LibOVR/Src/Kernel/OVR_String.h1290
-rw-r--r--LibOVR/Src/Kernel/OVR_StringHash.h178
-rw-r--r--LibOVR/Src/Kernel/OVR_String_FormatUtil.cpp84
-rw-r--r--LibOVR/Src/Kernel/OVR_String_PathUtil.cpp400
-rw-r--r--LibOVR/Src/Kernel/OVR_SysFile.cpp250
-rw-r--r--LibOVR/Src/Kernel/OVR_SysFile.h186
-rw-r--r--LibOVR/Src/Kernel/OVR_System.cpp140
-rw-r--r--LibOVR/Src/Kernel/OVR_System.h134
-rw-r--r--LibOVR/Src/Kernel/OVR_Threads.h792
-rw-r--r--LibOVR/Src/Kernel/OVR_ThreadsPthread.cpp1590
-rw-r--r--LibOVR/Src/Kernel/OVR_ThreadsWinAPI.cpp1988
-rw-r--r--LibOVR/Src/Kernel/OVR_Timer.cpp312
-rw-r--r--LibOVR/Src/Kernel/OVR_Timer.h200
-rw-r--r--LibOVR/Src/Kernel/OVR_Types.h912
-rw-r--r--LibOVR/Src/Kernel/OVR_UTF8Util.cpp1090
-rw-r--r--LibOVR/Src/Kernel/OVR_UTF8Util.h176
-rw-r--r--LibOVR/Src/OVR_Device.h1246
-rw-r--r--LibOVR/Src/OVR_DeviceConstants.h76
-rw-r--r--LibOVR/Src/OVR_DeviceHandle.cpp348
-rw-r--r--LibOVR/Src/OVR_DeviceHandle.h194
-rw-r--r--LibOVR/Src/OVR_DeviceImpl.cpp1574
-rw-r--r--LibOVR/Src/OVR_DeviceImpl.h857
-rw-r--r--LibOVR/Src/OVR_DeviceMessages.h324
-rw-r--r--LibOVR/Src/OVR_HIDDevice.h286
-rw-r--r--LibOVR/Src/OVR_HIDDeviceBase.h80
-rw-r--r--LibOVR/Src/OVR_HIDDeviceImpl.h406
-rw-r--r--LibOVR/Src/OVR_JSON.cpp1056
-rw-r--r--LibOVR/Src/OVR_JSON.h143
-rw-r--r--LibOVR/Src/OVR_LatencyTestImpl.cpp1572
-rw-r--r--LibOVR/Src/OVR_LatencyTestImpl.h268
-rw-r--r--LibOVR/Src/OVR_Linux_DeviceManager.cpp319
-rw-r--r--LibOVR/Src/OVR_Linux_DeviceManager.h111
-rw-r--r--LibOVR/Src/OVR_Linux_HIDDevice.cpp799
-rw-r--r--LibOVR/Src/OVR_Linux_HIDDevice.h124
-rw-r--r--LibOVR/Src/OVR_Linux_HMDDevice.cpp392
-rw-r--r--LibOVR/Src/OVR_Linux_HMDDevice.h156
-rw-r--r--LibOVR/Src/OVR_Linux_SensorDevice.cpp48
-rw-r--r--LibOVR/Src/OVR_OSX_DeviceManager.cpp698
-rw-r--r--LibOVR/Src/OVR_OSX_DeviceManager.h238
-rw-r--r--LibOVR/Src/OVR_OSX_HIDDevice.cpp1798
-rw-r--r--LibOVR/Src/OVR_OSX_HIDDevice.h298
-rw-r--r--LibOVR/Src/OVR_OSX_HMDDevice.cpp726
-rw-r--r--LibOVR/Src/OVR_OSX_HMDDevice.h296
-rw-r--r--LibOVR/Src/OVR_OSX_SensorDevice.cpp90
-rw-r--r--LibOVR/Src/OVR_Profile.cpp664
-rw-r--r--LibOVR/Src/OVR_Profile.h186
-rw-r--r--LibOVR/Src/OVR_SensorFilter.cpp400
-rw-r--r--LibOVR/Src/OVR_SensorFilter.h198
-rw-r--r--LibOVR/Src/OVR_SensorFusion.cpp813
-rw-r--r--LibOVR/Src/OVR_SensorFusion.h520
-rw-r--r--LibOVR/Src/OVR_SensorImpl.cpp1764
-rw-r--r--LibOVR/Src/OVR_SensorImpl.h416
-rw-r--r--LibOVR/Src/OVR_ThreadCommandQueue.cpp740
-rw-r--r--LibOVR/Src/OVR_ThreadCommandQueue.h616
-rw-r--r--LibOVR/Src/OVR_Win32_DeviceManager.cpp846
-rw-r--r--LibOVR/Src/OVR_Win32_DeviceManager.h292
-rw-r--r--LibOVR/Src/OVR_Win32_DeviceStatus.cpp700
-rw-r--r--LibOVR/Src/OVR_Win32_DeviceStatus.h202
-rw-r--r--LibOVR/Src/OVR_Win32_HIDDevice.cpp1274
-rw-r--r--LibOVR/Src/OVR_Win32_HIDDevice.h388
-rw-r--r--LibOVR/Src/OVR_Win32_HMDDevice.cpp916
-rw-r--r--LibOVR/Src/OVR_Win32_HMDDevice.h290
-rw-r--r--LibOVR/Src/OVR_Win32_SensorDevice.cpp94
-rw-r--r--LibOVR/Src/OVR_Win32_SensorDevice.h48
-rw-r--r--LibOVR/Src/Util/Util_LatencyTest.cpp1131
-rw-r--r--LibOVR/Src/Util/Util_LatencyTest.h320
-rw-r--r--LibOVR/Src/Util/Util_MagCalibration.cpp360
-rw-r--r--LibOVR/Src/Util/Util_MagCalibration.h236
-rw-r--r--LibOVR/Src/Util/Util_Render_Stereo.cpp625
-rw-r--r--LibOVR/Src/Util/Util_Render_Stereo.h599
94 files changed, 33124 insertions, 28804 deletions
diff --git a/LibOVR/Src/Kernel/OVR_Alg.cpp b/LibOVR/Src/Kernel/OVR_Alg.cpp
index ea82f2a..13b5595 100644
--- a/LibOVR/Src/Kernel/OVR_Alg.cpp
+++ b/LibOVR/Src/Kernel/OVR_Alg.cpp
@@ -1,46 +1,46 @@
-/************************************************************************************
-
-Filename : OVR_Alg.cpp
-Content : Static lookup tables for Alg functions
-Created : September 19, 2012
-Notes :
-
-Copyright : Copyright 2012 Oculus VR, Inc. All Rights reserved.
-
-Use of this software is subject to the terms of the Oculus license
-agreement provided at the time of installation or download, or which
-otherwise accompanies this software in either electronic or hard copy form.
-
-************************************************************************************/
-
-#include "OVR_Types.h"
-
-namespace OVR { namespace Alg {
-
-//------------------------------------------------------------------------
-extern const UByte UpperBitTable[256] =
-{
- 0,0,1,1,2,2,2,2,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,
- 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
- 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
- 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
- 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
- 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
- 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
- 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7
-};
-
-extern const UByte LowerBitTable[256] =
-{
- 8,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,
- 5,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,
- 6,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,
- 5,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,
- 7,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,
- 5,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,
- 6,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,
- 5,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0
-};
-
-
-}} // OVE::Alg
+/************************************************************************************
+
+Filename : OVR_Alg.cpp
+Content : Static lookup tables for Alg functions
+Created : September 19, 2012
+Notes :
+
+Copyright : Copyright 2012 Oculus VR, Inc. All Rights reserved.
+
+Use of this software is subject to the terms of the Oculus license
+agreement provided at the time of installation or download, or which
+otherwise accompanies this software in either electronic or hard copy form.
+
+************************************************************************************/
+
+#include "OVR_Types.h"
+
+namespace OVR { namespace Alg {
+
+//------------------------------------------------------------------------
+extern const UByte UpperBitTable[256] =
+{
+ 0,0,1,1,2,2,2,2,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,
+ 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
+ 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
+ 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
+ 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
+ 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
+ 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
+ 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7
+};
+
+extern const UByte LowerBitTable[256] =
+{
+ 8,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,
+ 5,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,
+ 6,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,
+ 5,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,
+ 7,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,
+ 5,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,
+ 6,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,
+ 5,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0
+};
+
+
+}} // OVE::Alg
diff --git a/LibOVR/Src/Kernel/OVR_Alg.h b/LibOVR/Src/Kernel/OVR_Alg.h
index 841e8f0..9e234c5 100644
--- a/LibOVR/Src/Kernel/OVR_Alg.h
+++ b/LibOVR/Src/Kernel/OVR_Alg.h
@@ -1,953 +1,953 @@
-/************************************************************************************
-
-PublicHeader: OVR.h
-Filename : OVR_Alg.h
-Content : Simple general purpose algorithms: Sort, Binary Search, etc.
-Created : September 19, 2012
-Notes :
-
-Copyright : Copyright 2012 Oculus VR, Inc. All Rights reserved.
-
-Use of this software is subject to the terms of the Oculus license
-agreement provided at the time of installation or download, or which
-otherwise accompanies this software in either electronic or hard copy form.
-
-************************************************************************************/
-
-#ifndef OVR_Alg_h
-#define OVR_Alg_h
-
-#include "OVR_Types.h"
-#include <string.h>
-
-namespace OVR { namespace Alg {
-
-
-//-----------------------------------------------------------------------------------
-// ***** Operator extensions
-
-template <typename T> OVR_FORCE_INLINE void Swap(T &a, T &b)
-{ T temp(a); a = b; b = temp; }
-
-
-// ***** min/max are not implemented in Visual Studio 6 standard STL
-
-template <typename T> OVR_FORCE_INLINE const T Min(const T a, const T b)
-{ return (a < b) ? a : b; }
-
-template <typename T> OVR_FORCE_INLINE const T Max(const T a, const T b)
-{ return (b < a) ? a : b; }
-
-template <typename T> OVR_FORCE_INLINE const T Clamp(const T v, const T minVal, const T maxVal)
-{ return Max<T>(minVal, Min<T>(v, maxVal)); }
-
-template <typename T> OVR_FORCE_INLINE int Chop(T f)
-{ return (int)f; }
-
-template <typename T> OVR_FORCE_INLINE T Lerp(T a, T b, T f)
-{ return (b - a) * f + a; }
-
-
-// These functions stand to fix a stupid VC++ warning (with /Wp64 on):
-// "warning C4267: 'argument' : conversion from 'size_t' to 'const unsigned', possible loss of data"
-// Use these functions instead of gmin/gmax if the argument has size
-// of the pointer to avoid the warning. Though, functionally they are
-// absolutelly the same as regular gmin/gmax.
-template <typename T> OVR_FORCE_INLINE const T PMin(const T a, const T b)
-{
- OVR_COMPILER_ASSERT(sizeof(T) == sizeof(UPInt));
- return (a < b) ? a : b;
-}
-template <typename T> OVR_FORCE_INLINE const T PMax(const T a, const T b)
-{
- OVR_COMPILER_ASSERT(sizeof(T) == sizeof(UPInt));
- return (b < a) ? a : b;
-}
-
-
-template <typename T> OVR_FORCE_INLINE const T Abs(const T v)
-{ return (v>=0) ? v : -v; }
-
-
-//-----------------------------------------------------------------------------------
-// ***** OperatorLess
-//
-template<class T> struct OperatorLess
-{
- static bool Compare(const T& a, const T& b)
- {
- return a < b;
- }
-};
-
-
-//-----------------------------------------------------------------------------------
-// ***** QuickSortSliced
-//
-// Sort any part of any array: plain, Array, ArrayPaged, ArrayUnsafe.
-// The range is specified with start, end, where "end" is exclusive!
-// The comparison predicate must be specified.
-template<class Array, class Less>
-void QuickSortSliced(Array& arr, UPInt start, UPInt end, Less less)
-{
- enum
- {
- Threshold = 9
- };
-
- if(end - start < 2) return;
-
- SPInt stack[80];
- SPInt* top = stack;
- SPInt base = (SPInt)start;
- SPInt limit = (SPInt)end;
-
- for(;;)
- {
- SPInt len = limit - base;
- SPInt i, j, pivot;
-
- if(len > Threshold)
- {
- // we use base + len/2 as the pivot
- pivot = base + len / 2;
- Swap(arr[base], arr[pivot]);
-
- i = base + 1;
- j = limit - 1;
-
- // now ensure that *i <= *base <= *j
- if(less(arr[j], arr[i])) Swap(arr[j], arr[i]);
- if(less(arr[base], arr[i])) Swap(arr[base], arr[i]);
- if(less(arr[j], arr[base])) Swap(arr[j], arr[base]);
-
- for(;;)
- {
- do i++; while( less(arr[i], arr[base]) );
- do j--; while( less(arr[base], arr[j]) );
-
- if( i > j )
- {
- break;
- }
-
- Swap(arr[i], arr[j]);
- }
-
- Swap(arr[base], arr[j]);
-
- // now, push the largest sub-array
- if(j - base > limit - i)
- {
- top[0] = base;
- top[1] = j;
- base = i;
- }
- else
- {
- top[0] = i;
- top[1] = limit;
- limit = j;
- }
- top += 2;
- }
- else
- {
- // the sub-array is small, perform insertion sort
- j = base;
- i = j + 1;
-
- for(; i < limit; j = i, i++)
- {
- for(; less(arr[j + 1], arr[j]); j--)
- {
- Swap(arr[j + 1], arr[j]);
- if(j == base)
- {
- break;
- }
- }
- }
- if(top > stack)
- {
- top -= 2;
- base = top[0];
- limit = top[1];
- }
- else
- {
- break;
- }
- }
- }
-}
-
-
-//-----------------------------------------------------------------------------------
-// ***** QuickSortSliced
-//
-// Sort any part of any array: plain, Array, ArrayPaged, ArrayUnsafe.
-// The range is specified with start, end, where "end" is exclusive!
-// The data type must have a defined "<" operator.
-template<class Array>
-void QuickSortSliced(Array& arr, UPInt start, UPInt end)
-{
- typedef typename Array::ValueType ValueType;
- QuickSortSliced(arr, start, end, OperatorLess<ValueType>::Compare);
-}
-
-// Same as corresponding G_QuickSortSliced but with checking array limits to avoid
-// crash in the case of wrong comparator functor.
-template<class Array, class Less>
-bool QuickSortSlicedSafe(Array& arr, UPInt start, UPInt end, Less less)
-{
- enum
- {
- Threshold = 9
- };
-
- if(end - start < 2) return true;
-
- SPInt stack[80];
- SPInt* top = stack;
- SPInt base = (SPInt)start;
- SPInt limit = (SPInt)end;
-
- for(;;)
- {
- SPInt len = limit - base;
- SPInt i, j, pivot;
-
- if(len > Threshold)
- {
- // we use base + len/2 as the pivot
- pivot = base + len / 2;
- Swap(arr[base], arr[pivot]);
-
- i = base + 1;
- j = limit - 1;
-
- // now ensure that *i <= *base <= *j
- if(less(arr[j], arr[i])) Swap(arr[j], arr[i]);
- if(less(arr[base], arr[i])) Swap(arr[base], arr[i]);
- if(less(arr[j], arr[base])) Swap(arr[j], arr[base]);
-
- for(;;)
- {
- do
- {
- i++;
- if (i >= limit)
- return false;
- } while( less(arr[i], arr[base]) );
- do
- {
- j--;
- if (j < 0)
- return false;
- } while( less(arr[base], arr[j]) );
-
- if( i > j )
- {
- break;
- }
-
- Swap(arr[i], arr[j]);
- }
-
- Swap(arr[base], arr[j]);
-
- // now, push the largest sub-array
- if(j - base > limit - i)
- {
- top[0] = base;
- top[1] = j;
- base = i;
- }
- else
- {
- top[0] = i;
- top[1] = limit;
- limit = j;
- }
- top += 2;
- }
- else
- {
- // the sub-array is small, perform insertion sort
- j = base;
- i = j + 1;
-
- for(; i < limit; j = i, i++)
- {
- for(; less(arr[j + 1], arr[j]); j--)
- {
- Swap(arr[j + 1], arr[j]);
- if(j == base)
- {
- break;
- }
- }
- }
- if(top > stack)
- {
- top -= 2;
- base = top[0];
- limit = top[1];
- }
- else
- {
- break;
- }
- }
- }
- return true;
-}
-
-template<class Array>
-bool QuickSortSlicedSafe(Array& arr, UPInt start, UPInt end)
-{
- typedef typename Array::ValueType ValueType;
- return QuickSortSlicedSafe(arr, start, end, OperatorLess<ValueType>::Compare);
-}
-
-//-----------------------------------------------------------------------------------
-// ***** QuickSort
-//
-// Sort an array Array, ArrayPaged, ArrayUnsafe.
-// The array must have GetSize() function.
-// The comparison predicate must be specified.
-template<class Array, class Less>
-void QuickSort(Array& arr, Less less)
-{
- QuickSortSliced(arr, 0, arr.GetSize(), less);
-}
-
-// checks for boundaries
-template<class Array, class Less>
-bool QuickSortSafe(Array& arr, Less less)
-{
- return QuickSortSlicedSafe(arr, 0, arr.GetSize(), less);
-}
-
-
-//-----------------------------------------------------------------------------------
-// ***** QuickSort
-//
-// Sort an array Array, ArrayPaged, ArrayUnsafe.
-// The array must have GetSize() function.
-// The data type must have a defined "<" operator.
-template<class Array>
-void QuickSort(Array& arr)
-{
- typedef typename Array::ValueType ValueType;
- QuickSortSliced(arr, 0, arr.GetSize(), OperatorLess<ValueType>::Compare);
-}
-
-template<class Array>
-bool QuickSortSafe(Array& arr)
-{
- typedef typename Array::ValueType ValueType;
- return QuickSortSlicedSafe(arr, 0, arr.GetSize(), OperatorLess<ValueType>::Compare);
-}
-
-//-----------------------------------------------------------------------------------
-// ***** InsertionSortSliced
-//
-// Sort any part of any array: plain, Array, ArrayPaged, ArrayUnsafe.
-// The range is specified with start, end, where "end" is exclusive!
-// The comparison predicate must be specified.
-// Unlike Quick Sort, the Insertion Sort works much slower in average,
-// but may be much faster on almost sorted arrays. Besides, it guarantees
-// that the elements will not be swapped if not necessary. For example,
-// an array with all equal elements will remain "untouched", while
-// Quick Sort will considerably shuffle the elements in this case.
-template<class Array, class Less>
-void InsertionSortSliced(Array& arr, UPInt start, UPInt end, Less less)
-{
- UPInt j = start;
- UPInt i = j + 1;
- UPInt limit = end;
-
- for(; i < limit; j = i, i++)
- {
- for(; less(arr[j + 1], arr[j]); j--)
- {
- Swap(arr[j + 1], arr[j]);
- if(j <= start)
- {
- break;
- }
- }
- }
-}
-
-
-//-----------------------------------------------------------------------------------
-// ***** InsertionSortSliced
-//
-// Sort any part of any array: plain, Array, ArrayPaged, ArrayUnsafe.
-// The range is specified with start, end, where "end" is exclusive!
-// The data type must have a defined "<" operator.
-template<class Array>
-void InsertionSortSliced(Array& arr, UPInt start, UPInt end)
-{
- typedef typename Array::ValueType ValueType;
- InsertionSortSliced(arr, start, end, OperatorLess<ValueType>::Compare);
-}
-
-//-----------------------------------------------------------------------------------
-// ***** InsertionSort
-//
-// Sort an array Array, ArrayPaged, ArrayUnsafe.
-// The array must have GetSize() function.
-// The comparison predicate must be specified.
-
-template<class Array, class Less>
-void InsertionSort(Array& arr, Less less)
-{
- InsertionSortSliced(arr, 0, arr.GetSize(), less);
-}
-
-//-----------------------------------------------------------------------------------
-// ***** InsertionSort
-//
-// Sort an array Array, ArrayPaged, ArrayUnsafe.
-// The array must have GetSize() function.
-// The data type must have a defined "<" operator.
-template<class Array>
-void InsertionSort(Array& arr)
-{
- typedef typename Array::ValueType ValueType;
- InsertionSortSliced(arr, 0, arr.GetSize(), OperatorLess<ValueType>::Compare);
-}
-
-
-
-//-----------------------------------------------------------------------------------
-// ***** LowerBoundSliced
-//
-template<class Array, class Value, class Less>
-UPInt LowerBoundSliced(const Array& arr, UPInt start, UPInt end, const Value& val, Less less)
-{
- SPInt first = (SPInt)start;
- SPInt len = (SPInt)(end - start);
- SPInt half;
- SPInt middle;
-
- while(len > 0)
- {
- half = len >> 1;
- middle = first + half;
- if(less(arr[middle], val))
- {
- first = middle + 1;
- len = len - half - 1;
- }
- else
- {
- len = half;
- }
- }
- return (UPInt)first;
-}
-
-
-//-----------------------------------------------------------------------------------
-// ***** LowerBoundSliced
-//
-template<class Array, class Value>
-UPInt LowerBoundSliced(const Array& arr, UPInt start, UPInt end, const Value& val)
-{
- return LowerBoundSliced(arr, start, end, val, OperatorLess<Value>::Compare);
-}
-
-//-----------------------------------------------------------------------------------
-// ***** LowerBoundSized
-//
-template<class Array, class Value>
-UPInt LowerBoundSized(const Array& arr, UPInt size, const Value& val)
-{
- return LowerBoundSliced(arr, 0, size, val, OperatorLess<Value>::Compare);
-}
-
-//-----------------------------------------------------------------------------------
-// ***** LowerBound
-//
-template<class Array, class Value, class Less>
-UPInt LowerBound(const Array& arr, const Value& val, Less less)
-{
- return LowerBoundSliced(arr, 0, arr.GetSize(), val, less);
-}
-
-
-//-----------------------------------------------------------------------------------
-// ***** LowerBound
-//
-template<class Array, class Value>
-UPInt LowerBound(const Array& arr, const Value& val)
-{
- return LowerBoundSliced(arr, 0, arr.GetSize(), val, OperatorLess<Value>::Compare);
-}
-
-
-
-//-----------------------------------------------------------------------------------
-// ***** UpperBoundSliced
-//
-template<class Array, class Value, class Less>
-UPInt UpperBoundSliced(const Array& arr, UPInt start, UPInt end, const Value& val, Less less)
-{
- SPInt first = (SPInt)start;
- SPInt len = (SPInt)(end - start);
- SPInt half;
- SPInt middle;
-
- while(len > 0)
- {
- half = len >> 1;
- middle = first + half;
- if(less(val, arr[middle]))
- {
- len = half;
- }
- else
- {
- first = middle + 1;
- len = len - half - 1;
- }
- }
- return (UPInt)first;
-}
-
-
-//-----------------------------------------------------------------------------------
-// ***** UpperBoundSliced
-//
-template<class Array, class Value>
-UPInt UpperBoundSliced(const Array& arr, UPInt start, UPInt end, const Value& val)
-{
- return UpperBoundSliced(arr, start, end, val, OperatorLess<Value>::Compare);
-}
-
-
-//-----------------------------------------------------------------------------------
-// ***** UpperBoundSized
-//
-template<class Array, class Value>
-UPInt UpperBoundSized(const Array& arr, UPInt size, const Value& val)
-{
- return UpperBoundSliced(arr, 0, size, val, OperatorLess<Value>::Compare);
-}
-
-
-//-----------------------------------------------------------------------------------
-// ***** UpperBound
-//
-template<class Array, class Value, class Less>
-UPInt UpperBound(const Array& arr, const Value& val, Less less)
-{
- return UpperBoundSliced(arr, 0, arr.GetSize(), val, less);
-}
-
-
-//-----------------------------------------------------------------------------------
-// ***** UpperBound
-//
-template<class Array, class Value>
-UPInt UpperBound(const Array& arr, const Value& val)
-{
- return UpperBoundSliced(arr, 0, arr.GetSize(), val, OperatorLess<Value>::Compare);
-}
-
-
-//-----------------------------------------------------------------------------------
-// ***** ReverseArray
-//
-template<class Array> void ReverseArray(Array& arr)
-{
- SPInt from = 0;
- SPInt to = arr.GetSize() - 1;
- while(from < to)
- {
- Swap(arr[from], arr[to]);
- ++from;
- --to;
- }
-}
-
-
-// ***** AppendArray
-//
-template<class CDst, class CSrc>
-void AppendArray(CDst& dst, const CSrc& src)
-{
- UPInt i;
- for(i = 0; i < src.GetSize(); i++)
- dst.PushBack(src[i]);
-}
-
-//-----------------------------------------------------------------------------------
-// ***** ArrayAdaptor
-//
-// A simple adapter that provides the GetSize() method and overloads
-// operator []. Used to wrap plain arrays in QuickSort and such.
-template<class T> class ArrayAdaptor
-{
-public:
- typedef T ValueType;
- ArrayAdaptor() : Data(0), Size(0) {}
- ArrayAdaptor(T* ptr, UPInt size) : Data(ptr), Size(size) {}
- UPInt GetSize() const { return Size; }
- const T& operator [] (UPInt i) const { return Data[i]; }
- T& operator [] (UPInt i) { return Data[i]; }
-private:
- T* Data;
- UPInt Size;
-};
-
-
-//-----------------------------------------------------------------------------------
-// ***** GConstArrayAdaptor
-//
-// A simple const adapter that provides the GetSize() method and overloads
-// operator []. Used to wrap plain arrays in LowerBound and such.
-template<class T> class ConstArrayAdaptor
-{
-public:
- typedef T ValueType;
- ConstArrayAdaptor() : Data(0), Size(0) {}
- ConstArrayAdaptor(const T* ptr, UPInt size) : Data(ptr), Size(size) {}
- UPInt GetSize() const { return Size; }
- const T& operator [] (UPInt i) const { return Data[i]; }
-private:
- const T* Data;
- UPInt Size;
-};
-
-
-
-//-----------------------------------------------------------------------------------
-extern const UByte UpperBitTable[256];
-extern const UByte LowerBitTable[256];
-
-
-
-//-----------------------------------------------------------------------------------
-inline UByte UpperBit(UPInt val)
-{
-#ifndef OVR_64BIT_POINTERS
-
- if (val & 0xFFFF0000)
- {
- return (val & 0xFF000000) ?
- UpperBitTable[(val >> 24) ] + 24:
- UpperBitTable[(val >> 16) & 0xFF] + 16;
- }
- return (val & 0xFF00) ?
- UpperBitTable[(val >> 8) & 0xFF] + 8:
- UpperBitTable[(val ) & 0xFF];
-
-#else
-
- if (val & 0xFFFFFFFF00000000)
- {
- if (val & 0xFFFF000000000000)
- {
- return (val & 0xFF00000000000000) ?
- UpperBitTable[(val >> 56) ] + 56:
- UpperBitTable[(val >> 48) & 0xFF] + 48;
- }
- return (val & 0xFF0000000000) ?
- UpperBitTable[(val >> 40) & 0xFF] + 40:
- UpperBitTable[(val >> 32) & 0xFF] + 32;
- }
- else
- {
- if (val & 0xFFFF0000)
- {
- return (val & 0xFF000000) ?
- UpperBitTable[(val >> 24) ] + 24:
- UpperBitTable[(val >> 16) & 0xFF] + 16;
- }
- return (val & 0xFF00) ?
- UpperBitTable[(val >> 8) & 0xFF] + 8:
- UpperBitTable[(val ) & 0xFF];
- }
-
-#endif
-}
-
-//-----------------------------------------------------------------------------------
-inline UByte LowerBit(UPInt val)
-{
-#ifndef OVR_64BIT_POINTERS
-
- if (val & 0xFFFF)
- {
- return (val & 0xFF) ?
- LowerBitTable[ val & 0xFF]:
- LowerBitTable[(val >> 8) & 0xFF] + 8;
- }
- return (val & 0xFF0000) ?
- LowerBitTable[(val >> 16) & 0xFF] + 16:
- LowerBitTable[(val >> 24) & 0xFF] + 24;
-
-#else
-
- if (val & 0xFFFFFFFF)
- {
- if (val & 0xFFFF)
- {
- return (val & 0xFF) ?
- LowerBitTable[ val & 0xFF]:
- LowerBitTable[(val >> 8) & 0xFF] + 8;
- }
- return (val & 0xFF0000) ?
- LowerBitTable[(val >> 16) & 0xFF] + 16:
- LowerBitTable[(val >> 24) & 0xFF] + 24;
- }
- else
- {
- if (val & 0xFFFF00000000)
- {
- return (val & 0xFF00000000) ?
- LowerBitTable[(val >> 32) & 0xFF] + 32:
- LowerBitTable[(val >> 40) & 0xFF] + 40;
- }
- return (val & 0xFF000000000000) ?
- LowerBitTable[(val >> 48) & 0xFF] + 48:
- LowerBitTable[(val >> 56) & 0xFF] + 56;
- }
-
-#endif
-}
-
-
-
-// ******* Special (optimized) memory routines
-// Note: null (bad) pointer is not tested
-class MemUtil
-{
-public:
-
- // Memory compare
- static int Cmp (const void* p1, const void* p2, UPInt byteCount) { return memcmp(p1, p2, byteCount); }
- static int Cmp16(const void* p1, const void* p2, UPInt int16Count);
- static int Cmp32(const void* p1, const void* p2, UPInt int32Count);
- static int Cmp64(const void* p1, const void* p2, UPInt int64Count);
-};
-
-// ** Inline Implementation
-
-inline int MemUtil::Cmp16(const void* p1, const void* p2, UPInt int16Count)
-{
- SInt16* pa = (SInt16*)p1;
- SInt16* pb = (SInt16*)p2;
- unsigned ic = 0;
- if (int16Count == 0)
- return 0;
- while (pa[ic] == pb[ic])
- if (++ic==int16Count)
- return 0;
- return pa[ic] > pb[ic] ? 1 : -1;
-}
-inline int MemUtil::Cmp32(const void* p1, const void* p2, UPInt int32Count)
-{
- SInt32* pa = (SInt32*)p1;
- SInt32* pb = (SInt32*)p2;
- unsigned ic = 0;
- if (int32Count == 0)
- return 0;
- while (pa[ic] == pb[ic])
- if (++ic==int32Count)
- return 0;
- return pa[ic] > pb[ic] ? 1 : -1;
-}
-inline int MemUtil::Cmp64(const void* p1, const void* p2, UPInt int64Count)
-{
- SInt64* pa = (SInt64*)p1;
- SInt64* pb = (SInt64*)p2;
- unsigned ic = 0;
- if (int64Count == 0)
- return 0;
- while (pa[ic] == pb[ic])
- if (++ic==int64Count)
- return 0;
- return pa[ic] > pb[ic] ? 1 : -1;
-}
-
-// ** End Inline Implementation
-
-
-//-----------------------------------------------------------------------------------
-// ******* Byte Order Conversions
-namespace ByteUtil {
-
- // *** Swap Byte Order
-
- // Swap the byte order of a byte array
- inline void SwapOrder(void* pv, int size)
- {
- UByte* pb = (UByte*)pv;
- UByte temp;
- for (int i = 0; i < size>>1; i++)
- {
- temp = pb[size-1-i];
- pb[size-1-i] = pb[i];
- pb[i] = temp;
- }
- }
-
- // Swap the byte order of primitive types
- inline UByte SwapOrder(UByte v) { return v; }
- inline SByte SwapOrder(SByte v) { return v; }
- inline UInt16 SwapOrder(UInt16 v) { return UInt16(v>>8)|UInt16(v<<8); }
- inline SInt16 SwapOrder(SInt16 v) { return SInt16((UInt16(v)>>8)|(v<<8)); }
- inline UInt32 SwapOrder(UInt32 v) { return (v>>24)|((v&0x00FF0000)>>8)|((v&0x0000FF00)<<8)|(v<<24); }
- inline SInt32 SwapOrder(SInt32 p) { return (SInt32)SwapOrder(UInt32(p)); }
- inline UInt64 SwapOrder(UInt64 v)
- {
- return (v>>56) |
- ((v&UInt64(0x00FF000000000000))>>40) |
- ((v&UInt64(0x0000FF0000000000))>>24) |
- ((v&UInt64(0x000000FF00000000))>>8) |
- ((v&UInt64(0x00000000FF000000))<<8) |
- ((v&UInt64(0x0000000000FF0000))<<24) |
- ((v&UInt64(0x000000000000FF00))<<40) |
- (v<<56);
- }
- inline SInt64 SwapOrder(SInt64 v) { return (SInt64)SwapOrder(UInt64(v)); }
- inline float SwapOrder(float p)
- {
- union {
- float p;
- UInt32 v;
- } u;
- u.p = p;
- u.v = SwapOrder(u.v);
- return u.p;
- }
-
- inline double SwapOrder(double p)
- {
- union {
- double p;
- UInt64 v;
- } u;
- u.p = p;
- u.v = SwapOrder(u.v);
- return u.p;
- }
-
- // *** Byte-order conversion
-
-#if (OVR_BYTE_ORDER == OVR_LITTLE_ENDIAN)
- // Little Endian to System (LE)
- inline UByte LEToSystem(UByte v) { return v; }
- inline SByte LEToSystem(SByte v) { return v; }
- inline UInt16 LEToSystem(UInt16 v) { return v; }
- inline SInt16 LEToSystem(SInt16 v) { return v; }
- inline UInt32 LEToSystem(UInt32 v) { return v; }
- inline SInt32 LEToSystem(SInt32 v) { return v; }
- inline UInt64 LEToSystem(UInt64 v) { return v; }
- inline SInt64 LEToSystem(SInt64 v) { return v; }
- inline float LEToSystem(float v) { return v; }
- inline double LEToSystem(double v) { return v; }
-
- // Big Endian to System (LE)
- inline UByte BEToSystem(UByte v) { return SwapOrder(v); }
- inline SByte BEToSystem(SByte v) { return SwapOrder(v); }
- inline UInt16 BEToSystem(UInt16 v) { return SwapOrder(v); }
- inline SInt16 BEToSystem(SInt16 v) { return SwapOrder(v); }
- inline UInt32 BEToSystem(UInt32 v) { return SwapOrder(v); }
- inline SInt32 BEToSystem(SInt32 v) { return SwapOrder(v); }
- inline UInt64 BEToSystem(UInt64 v) { return SwapOrder(v); }
- inline SInt64 BEToSystem(SInt64 v) { return SwapOrder(v); }
- inline float BEToSystem(float v) { return SwapOrder(v); }
- inline double BEToSystem(double v) { return SwapOrder(v); }
-
- // System (LE) to Little Endian
- inline UByte SystemToLE(UByte v) { return v; }
- inline SByte SystemToLE(SByte v) { return v; }
- inline UInt16 SystemToLE(UInt16 v) { return v; }
- inline SInt16 SystemToLE(SInt16 v) { return v; }
- inline UInt32 SystemToLE(UInt32 v) { return v; }
- inline SInt32 SystemToLE(SInt32 v) { return v; }
- inline UInt64 SystemToLE(UInt64 v) { return v; }
- inline SInt64 SystemToLE(SInt64 v) { return v; }
- inline float SystemToLE(float v) { return v; }
- inline double SystemToLE(double v) { return v; }
-
- // System (LE) to Big Endian
- inline UByte SystemToBE(UByte v) { return SwapOrder(v); }
- inline SByte SystemToBE(SByte v) { return SwapOrder(v); }
- inline UInt16 SystemToBE(UInt16 v) { return SwapOrder(v); }
- inline SInt16 SystemToBE(SInt16 v) { return SwapOrder(v); }
- inline UInt32 SystemToBE(UInt32 v) { return SwapOrder(v); }
- inline SInt32 SystemToBE(SInt32 v) { return SwapOrder(v); }
- inline UInt64 SystemToBE(UInt64 v) { return SwapOrder(v); }
- inline SInt64 SystemToBE(SInt64 v) { return SwapOrder(v); }
- inline float SystemToBE(float v) { return SwapOrder(v); }
- inline double SystemToBE(double v) { return SwapOrder(v); }
-
-#elif (OVR_BYTE_ORDER == OVR_BIG_ENDIAN)
- // Little Endian to System (BE)
- inline UByte LEToSystem(UByte v) { return SwapOrder(v); }
- inline SByte LEToSystem(SByte v) { return SwapOrder(v); }
- inline UInt16 LEToSystem(UInt16 v) { return SwapOrder(v); }
- inline SInt16 LEToSystem(SInt16 v) { return SwapOrder(v); }
- inline UInt32 LEToSystem(UInt32 v) { return SwapOrder(v); }
- inline SInt32 LEToSystem(SInt32 v) { return SwapOrder(v); }
- inline UInt64 LEToSystem(UInt64 v) { return SwapOrder(v); }
- inline SInt64 LEToSystem(SInt64 v) { return SwapOrder(v); }
- inline float LEToSystem(float v) { return SwapOrder(v); }
- inline double LEToSystem(double v) { return SwapOrder(v); }
-
- // Big Endian to System (BE)
- inline UByte BEToSystem(UByte v) { return v; }
- inline SByte BEToSystem(SByte v) { return v; }
- inline UInt16 BEToSystem(UInt16 v) { return v; }
- inline SInt16 BEToSystem(SInt16 v) { return v; }
- inline UInt32 BEToSystem(UInt32 v) { return v; }
- inline SInt32 BEToSystem(SInt32 v) { return v; }
- inline UInt64 BEToSystem(UInt64 v) { return v; }
- inline SInt64 BEToSystem(SInt64 v) { return v; }
- inline float BEToSystem(float v) { return v; }
- inline double BEToSystem(double v) { return v; }
-
- // System (BE) to Little Endian
- inline UByte SystemToLE(UByte v) { return SwapOrder(v); }
- inline SByte SystemToLE(SByte v) { return SwapOrder(v); }
- inline UInt16 SystemToLE(UInt16 v) { return SwapOrder(v); }
- inline SInt16 SystemToLE(SInt16 v) { return SwapOrder(v); }
- inline UInt32 SystemToLE(UInt32 v) { return SwapOrder(v); }
- inline SInt32 SystemToLE(SInt32 v) { return SwapOrder(v); }
- inline UInt64 SystemToLE(UInt64 v) { return SwapOrder(v); }
- inline SInt64 SystemToLE(SInt64 v) { return SwapOrder(v); }
- inline float SystemToLE(float v) { return SwapOrder(v); }
- inline double SystemToLE(double v) { return SwapOrder(v); }
-
- // System (BE) to Big Endian
- inline UByte SystemToBE(UByte v) { return v; }
- inline SByte SystemToBE(SByte v) { return v; }
- inline UInt16 SystemToBE(UInt16 v) { return v; }
- inline SInt16 SystemToBE(SInt16 v) { return v; }
- inline UInt32 SystemToBE(UInt32 v) { return v; }
- inline SInt32 SystemToBE(SInt32 v) { return v; }
- inline UInt64 SystemToBE(UInt64 v) { return v; }
- inline SInt64 SystemToBE(SInt64 v) { return v; }
- inline float SystemToBE(float v) { return v; }
- inline double SystemToBE(double v) { return v; }
-
-#else
- #error "OVR_BYTE_ORDER must be defined to OVR_LITTLE_ENDIAN or OVR_BIG_ENDIAN"
-#endif
-
-} // namespace ByteUtil
-
-
-
-}} // OVR::Alg
-
-#endif
+/************************************************************************************
+
+PublicHeader: OVR.h
+Filename : OVR_Alg.h
+Content : Simple general purpose algorithms: Sort, Binary Search, etc.
+Created : September 19, 2012
+Notes :
+
+Copyright : Copyright 2012 Oculus VR, Inc. All Rights reserved.
+
+Use of this software is subject to the terms of the Oculus license
+agreement provided at the time of installation or download, or which
+otherwise accompanies this software in either electronic or hard copy form.
+
+************************************************************************************/
+
+#ifndef OVR_Alg_h
+#define OVR_Alg_h
+
+#include "OVR_Types.h"
+#include <string.h>
+
+namespace OVR { namespace Alg {
+
+
+//-----------------------------------------------------------------------------------
+// ***** Operator extensions
+
+template <typename T> OVR_FORCE_INLINE void Swap(T &a, T &b)
+{ T temp(a); a = b; b = temp; }
+
+
+// ***** min/max are not implemented in Visual Studio 6 standard STL
+
+template <typename T> OVR_FORCE_INLINE const T Min(const T a, const T b)
+{ return (a < b) ? a : b; }
+
+template <typename T> OVR_FORCE_INLINE const T Max(const T a, const T b)
+{ return (b < a) ? a : b; }
+
+template <typename T> OVR_FORCE_INLINE const T Clamp(const T v, const T minVal, const T maxVal)
+{ return Max<T>(minVal, Min<T>(v, maxVal)); }
+
+template <typename T> OVR_FORCE_INLINE int Chop(T f)
+{ return (int)f; }
+
+template <typename T> OVR_FORCE_INLINE T Lerp(T a, T b, T f)
+{ return (b - a) * f + a; }
+
+
+// These functions stand to fix a stupid VC++ warning (with /Wp64 on):
+// "warning C4267: 'argument' : conversion from 'size_t' to 'const unsigned', possible loss of data"
+// Use these functions instead of gmin/gmax if the argument has size
+// of the pointer to avoid the warning. Though, functionally they are
+// absolutelly the same as regular gmin/gmax.
+template <typename T> OVR_FORCE_INLINE const T PMin(const T a, const T b)
+{
+ OVR_COMPILER_ASSERT(sizeof(T) == sizeof(UPInt));
+ return (a < b) ? a : b;
+}
+template <typename T> OVR_FORCE_INLINE const T PMax(const T a, const T b)
+{
+ OVR_COMPILER_ASSERT(sizeof(T) == sizeof(UPInt));
+ return (b < a) ? a : b;
+}
+
+
+template <typename T> OVR_FORCE_INLINE const T Abs(const T v)
+{ return (v>=0) ? v : -v; }
+
+
+//-----------------------------------------------------------------------------------
+// ***** OperatorLess
+//
+template<class T> struct OperatorLess
+{
+ static bool Compare(const T& a, const T& b)
+ {
+ return a < b;
+ }
+};
+
+
+//-----------------------------------------------------------------------------------
+// ***** QuickSortSliced
+//
+// Sort any part of any array: plain, Array, ArrayPaged, ArrayUnsafe.
+// The range is specified with start, end, where "end" is exclusive!
+// The comparison predicate must be specified.
+template<class Array, class Less>
+void QuickSortSliced(Array& arr, UPInt start, UPInt end, Less less)
+{
+ enum
+ {
+ Threshold = 9
+ };
+
+ if(end - start < 2) return;
+
+ SPInt stack[80];
+ SPInt* top = stack;
+ SPInt base = (SPInt)start;
+ SPInt limit = (SPInt)end;
+
+ for(;;)
+ {
+ SPInt len = limit - base;
+ SPInt i, j, pivot;
+
+ if(len > Threshold)
+ {
+ // we use base + len/2 as the pivot
+ pivot = base + len / 2;
+ Swap(arr[base], arr[pivot]);
+
+ i = base + 1;
+ j = limit - 1;
+
+ // now ensure that *i <= *base <= *j
+ if(less(arr[j], arr[i])) Swap(arr[j], arr[i]);
+ if(less(arr[base], arr[i])) Swap(arr[base], arr[i]);
+ if(less(arr[j], arr[base])) Swap(arr[j], arr[base]);
+
+ for(;;)
+ {
+ do i++; while( less(arr[i], arr[base]) );
+ do j--; while( less(arr[base], arr[j]) );
+
+ if( i > j )
+ {
+ break;
+ }
+
+ Swap(arr[i], arr[j]);
+ }
+
+ Swap(arr[base], arr[j]);
+
+ // now, push the largest sub-array
+ if(j - base > limit - i)
+ {
+ top[0] = base;
+ top[1] = j;
+ base = i;
+ }
+ else
+ {
+ top[0] = i;
+ top[1] = limit;
+ limit = j;
+ }
+ top += 2;
+ }
+ else
+ {
+ // the sub-array is small, perform insertion sort
+ j = base;
+ i = j + 1;
+
+ for(; i < limit; j = i, i++)
+ {
+ for(; less(arr[j + 1], arr[j]); j--)
+ {
+ Swap(arr[j + 1], arr[j]);
+ if(j == base)
+ {
+ break;
+ }
+ }
+ }
+ if(top > stack)
+ {
+ top -= 2;
+ base = top[0];
+ limit = top[1];
+ }
+ else
+ {
+ break;
+ }
+ }
+ }
+}
+
+
+//-----------------------------------------------------------------------------------
+// ***** QuickSortSliced
+//
+// Sort any part of any array: plain, Array, ArrayPaged, ArrayUnsafe.
+// The range is specified with start, end, where "end" is exclusive!
+// The data type must have a defined "<" operator.
+template<class Array>
+void QuickSortSliced(Array& arr, UPInt start, UPInt end)
+{
+ typedef typename Array::ValueType ValueType;
+ QuickSortSliced(arr, start, end, OperatorLess<ValueType>::Compare);
+}
+
+// Same as corresponding G_QuickSortSliced but with checking array limits to avoid
+// crash in the case of wrong comparator functor.
+template<class Array, class Less>
+bool QuickSortSlicedSafe(Array& arr, UPInt start, UPInt end, Less less)
+{
+ enum
+ {
+ Threshold = 9
+ };
+
+ if(end - start < 2) return true;
+
+ SPInt stack[80];
+ SPInt* top = stack;
+ SPInt base = (SPInt)start;
+ SPInt limit = (SPInt)end;
+
+ for(;;)
+ {
+ SPInt len = limit - base;
+ SPInt i, j, pivot;
+
+ if(len > Threshold)
+ {
+ // we use base + len/2 as the pivot
+ pivot = base + len / 2;
+ Swap(arr[base], arr[pivot]);
+
+ i = base + 1;
+ j = limit - 1;
+
+ // now ensure that *i <= *base <= *j
+ if(less(arr[j], arr[i])) Swap(arr[j], arr[i]);
+ if(less(arr[base], arr[i])) Swap(arr[base], arr[i]);
+ if(less(arr[j], arr[base])) Swap(arr[j], arr[base]);
+
+ for(;;)
+ {
+ do
+ {
+ i++;
+ if (i >= limit)
+ return false;
+ } while( less(arr[i], arr[base]) );
+ do
+ {
+ j--;
+ if (j < 0)
+ return false;
+ } while( less(arr[base], arr[j]) );
+
+ if( i > j )
+ {
+ break;
+ }
+
+ Swap(arr[i], arr[j]);
+ }
+
+ Swap(arr[base], arr[j]);
+
+ // now, push the largest sub-array
+ if(j - base > limit - i)
+ {
+ top[0] = base;
+ top[1] = j;
+ base = i;
+ }
+ else
+ {
+ top[0] = i;
+ top[1] = limit;
+ limit = j;
+ }
+ top += 2;
+ }
+ else
+ {
+ // the sub-array is small, perform insertion sort
+ j = base;
+ i = j + 1;
+
+ for(; i < limit; j = i, i++)
+ {
+ for(; less(arr[j + 1], arr[j]); j--)
+ {
+ Swap(arr[j + 1], arr[j]);
+ if(j == base)
+ {
+ break;
+ }
+ }
+ }
+ if(top > stack)
+ {
+ top -= 2;
+ base = top[0];
+ limit = top[1];
+ }
+ else
+ {
+ break;
+ }
+ }
+ }
+ return true;
+}
+
+template<class Array>
+bool QuickSortSlicedSafe(Array& arr, UPInt start, UPInt end)
+{
+ typedef typename Array::ValueType ValueType;
+ return QuickSortSlicedSafe(arr, start, end, OperatorLess<ValueType>::Compare);
+}
+
+//-----------------------------------------------------------------------------------
+// ***** QuickSort
+//
+// Sort an array Array, ArrayPaged, ArrayUnsafe.
+// The array must have GetSize() function.
+// The comparison predicate must be specified.
+template<class Array, class Less>
+void QuickSort(Array& arr, Less less)
+{
+ QuickSortSliced(arr, 0, arr.GetSize(), less);
+}
+
+// checks for boundaries
+template<class Array, class Less>
+bool QuickSortSafe(Array& arr, Less less)
+{
+ return QuickSortSlicedSafe(arr, 0, arr.GetSize(), less);
+}
+
+
+//-----------------------------------------------------------------------------------
+// ***** QuickSort
+//
+// Sort an array Array, ArrayPaged, ArrayUnsafe.
+// The array must have GetSize() function.
+// The data type must have a defined "<" operator.
+template<class Array>
+void QuickSort(Array& arr)
+{
+ typedef typename Array::ValueType ValueType;
+ QuickSortSliced(arr, 0, arr.GetSize(), OperatorLess<ValueType>::Compare);
+}
+
+template<class Array>
+bool QuickSortSafe(Array& arr)
+{
+ typedef typename Array::ValueType ValueType;
+ return QuickSortSlicedSafe(arr, 0, arr.GetSize(), OperatorLess<ValueType>::Compare);
+}
+
+//-----------------------------------------------------------------------------------
+// ***** InsertionSortSliced
+//
+// Sort any part of any array: plain, Array, ArrayPaged, ArrayUnsafe.
+// The range is specified with start, end, where "end" is exclusive!
+// The comparison predicate must be specified.
+// Unlike Quick Sort, the Insertion Sort works much slower in average,
+// but may be much faster on almost sorted arrays. Besides, it guarantees
+// that the elements will not be swapped if not necessary. For example,
+// an array with all equal elements will remain "untouched", while
+// Quick Sort will considerably shuffle the elements in this case.
+template<class Array, class Less>
+void InsertionSortSliced(Array& arr, UPInt start, UPInt end, Less less)
+{
+ UPInt j = start;
+ UPInt i = j + 1;
+ UPInt limit = end;
+
+ for(; i < limit; j = i, i++)
+ {
+ for(; less(arr[j + 1], arr[j]); j--)
+ {
+ Swap(arr[j + 1], arr[j]);
+ if(j <= start)
+ {
+ break;
+ }
+ }
+ }
+}
+
+
+//-----------------------------------------------------------------------------------
+// ***** InsertionSortSliced
+//
+// Sort any part of any array: plain, Array, ArrayPaged, ArrayUnsafe.
+// The range is specified with start, end, where "end" is exclusive!
+// The data type must have a defined "<" operator.
+template<class Array>
+void InsertionSortSliced(Array& arr, UPInt start, UPInt end)
+{
+ typedef typename Array::ValueType ValueType;
+ InsertionSortSliced(arr, start, end, OperatorLess<ValueType>::Compare);
+}
+
+//-----------------------------------------------------------------------------------
+// ***** InsertionSort
+//
+// Sort an array Array, ArrayPaged, ArrayUnsafe.
+// The array must have GetSize() function.
+// The comparison predicate must be specified.
+
+template<class Array, class Less>
+void InsertionSort(Array& arr, Less less)
+{
+ InsertionSortSliced(arr, 0, arr.GetSize(), less);
+}
+
+//-----------------------------------------------------------------------------------
+// ***** InsertionSort
+//
+// Sort an array Array, ArrayPaged, ArrayUnsafe.
+// The array must have GetSize() function.
+// The data type must have a defined "<" operator.
+template<class Array>
+void InsertionSort(Array& arr)
+{
+ typedef typename Array::ValueType ValueType;
+ InsertionSortSliced(arr, 0, arr.GetSize(), OperatorLess<ValueType>::Compare);
+}
+
+
+
+//-----------------------------------------------------------------------------------
+// ***** LowerBoundSliced
+//
+template<class Array, class Value, class Less>
+UPInt LowerBoundSliced(const Array& arr, UPInt start, UPInt end, const Value& val, Less less)
+{
+ SPInt first = (SPInt)start;
+ SPInt len = (SPInt)(end - start);
+ SPInt half;
+ SPInt middle;
+
+ while(len > 0)
+ {
+ half = len >> 1;
+ middle = first + half;
+ if(less(arr[middle], val))
+ {
+ first = middle + 1;
+ len = len - half - 1;
+ }
+ else
+ {
+ len = half;
+ }
+ }
+ return (UPInt)first;
+}
+
+
+//-----------------------------------------------------------------------------------
+// ***** LowerBoundSliced
+//
+template<class Array, class Value>
+UPInt LowerBoundSliced(const Array& arr, UPInt start, UPInt end, const Value& val)
+{
+ return LowerBoundSliced(arr, start, end, val, OperatorLess<Value>::Compare);
+}
+
+//-----------------------------------------------------------------------------------
+// ***** LowerBoundSized
+//
+template<class Array, class Value>
+UPInt LowerBoundSized(const Array& arr, UPInt size, const Value& val)
+{
+ return LowerBoundSliced(arr, 0, size, val, OperatorLess<Value>::Compare);
+}
+
+//-----------------------------------------------------------------------------------
+// ***** LowerBound
+//
+template<class Array, class Value, class Less>
+UPInt LowerBound(const Array& arr, const Value& val, Less less)
+{
+ return LowerBoundSliced(arr, 0, arr.GetSize(), val, less);
+}
+
+
+//-----------------------------------------------------------------------------------
+// ***** LowerBound
+//
+template<class Array, class Value>
+UPInt LowerBound(const Array& arr, const Value& val)
+{
+ return LowerBoundSliced(arr, 0, arr.GetSize(), val, OperatorLess<Value>::Compare);
+}
+
+
+
+//-----------------------------------------------------------------------------------
+// ***** UpperBoundSliced
+//
+template<class Array, class Value, class Less>
+UPInt UpperBoundSliced(const Array& arr, UPInt start, UPInt end, const Value& val, Less less)
+{
+ SPInt first = (SPInt)start;
+ SPInt len = (SPInt)(end - start);
+ SPInt half;
+ SPInt middle;
+
+ while(len > 0)
+ {
+ half = len >> 1;
+ middle = first + half;
+ if(less(val, arr[middle]))
+ {
+ len = half;
+ }
+ else
+ {
+ first = middle + 1;
+ len = len - half - 1;
+ }
+ }
+ return (UPInt)first;
+}
+
+
+//-----------------------------------------------------------------------------------
+// ***** UpperBoundSliced
+//
+template<class Array, class Value>
+UPInt UpperBoundSliced(const Array& arr, UPInt start, UPInt end, const Value& val)
+{
+ return UpperBoundSliced(arr, start, end, val, OperatorLess<Value>::Compare);
+}
+
+
+//-----------------------------------------------------------------------------------
+// ***** UpperBoundSized
+//
+template<class Array, class Value>
+UPInt UpperBoundSized(const Array& arr, UPInt size, const Value& val)
+{
+ return UpperBoundSliced(arr, 0, size, val, OperatorLess<Value>::Compare);
+}
+
+
+//-----------------------------------------------------------------------------------
+// ***** UpperBound
+//
+template<class Array, class Value, class Less>
+UPInt UpperBound(const Array& arr, const Value& val, Less less)
+{
+ return UpperBoundSliced(arr, 0, arr.GetSize(), val, less);
+}
+
+
+//-----------------------------------------------------------------------------------
+// ***** UpperBound
+//
+template<class Array, class Value>
+UPInt UpperBound(const Array& arr, const Value& val)
+{
+ return UpperBoundSliced(arr, 0, arr.GetSize(), val, OperatorLess<Value>::Compare);
+}
+
+
+//-----------------------------------------------------------------------------------
+// ***** ReverseArray
+//
+template<class Array> void ReverseArray(Array& arr)
+{
+ SPInt from = 0;
+ SPInt to = arr.GetSize() - 1;
+ while(from < to)
+ {
+ Swap(arr[from], arr[to]);
+ ++from;
+ --to;
+ }
+}
+
+
+// ***** AppendArray
+//
+template<class CDst, class CSrc>
+void AppendArray(CDst& dst, const CSrc& src)
+{
+ UPInt i;
+ for(i = 0; i < src.GetSize(); i++)
+ dst.PushBack(src[i]);
+}
+
+//-----------------------------------------------------------------------------------
+// ***** ArrayAdaptor
+//
+// A simple adapter that provides the GetSize() method and overloads
+// operator []. Used to wrap plain arrays in QuickSort and such.
+template<class T> class ArrayAdaptor
+{
+public:
+ typedef T ValueType;
+ ArrayAdaptor() : Data(0), Size(0) {}
+ ArrayAdaptor(T* ptr, UPInt size) : Data(ptr), Size(size) {}
+ UPInt GetSize() const { return Size; }
+ const T& operator [] (UPInt i) const { return Data[i]; }
+ T& operator [] (UPInt i) { return Data[i]; }
+private:
+ T* Data;
+ UPInt Size;
+};
+
+
+//-----------------------------------------------------------------------------------
+// ***** GConstArrayAdaptor
+//
+// A simple const adapter that provides the GetSize() method and overloads
+// operator []. Used to wrap plain arrays in LowerBound and such.
+template<class T> class ConstArrayAdaptor
+{
+public:
+ typedef T ValueType;
+ ConstArrayAdaptor() : Data(0), Size(0) {}
+ ConstArrayAdaptor(const T* ptr, UPInt size) : Data(ptr), Size(size) {}
+ UPInt GetSize() const { return Size; }
+ const T& operator [] (UPInt i) const { return Data[i]; }
+private:
+ const T* Data;
+ UPInt Size;
+};
+
+
+
+//-----------------------------------------------------------------------------------
+extern const UByte UpperBitTable[256];
+extern const UByte LowerBitTable[256];
+
+
+
+//-----------------------------------------------------------------------------------
+inline UByte UpperBit(UPInt val)
+{
+#ifndef OVR_64BIT_POINTERS
+
+ if (val & 0xFFFF0000)
+ {
+ return (val & 0xFF000000) ?
+ UpperBitTable[(val >> 24) ] + 24:
+ UpperBitTable[(val >> 16) & 0xFF] + 16;
+ }
+ return (val & 0xFF00) ?
+ UpperBitTable[(val >> 8) & 0xFF] + 8:
+ UpperBitTable[(val ) & 0xFF];
+
+#else
+
+ if (val & 0xFFFFFFFF00000000)
+ {
+ if (val & 0xFFFF000000000000)
+ {
+ return (val & 0xFF00000000000000) ?
+ UpperBitTable[(val >> 56) ] + 56:
+ UpperBitTable[(val >> 48) & 0xFF] + 48;
+ }
+ return (val & 0xFF0000000000) ?
+ UpperBitTable[(val >> 40) & 0xFF] + 40:
+ UpperBitTable[(val >> 32) & 0xFF] + 32;
+ }
+ else
+ {
+ if (val & 0xFFFF0000)
+ {
+ return (val & 0xFF000000) ?
+ UpperBitTable[(val >> 24) ] + 24:
+ UpperBitTable[(val >> 16) & 0xFF] + 16;
+ }
+ return (val & 0xFF00) ?
+ UpperBitTable[(val >> 8) & 0xFF] + 8:
+ UpperBitTable[(val ) & 0xFF];
+ }
+
+#endif
+}
+
+//-----------------------------------------------------------------------------------
+inline UByte LowerBit(UPInt val)
+{
+#ifndef OVR_64BIT_POINTERS
+
+ if (val & 0xFFFF)
+ {
+ return (val & 0xFF) ?
+ LowerBitTable[ val & 0xFF]:
+ LowerBitTable[(val >> 8) & 0xFF] + 8;
+ }
+ return (val & 0xFF0000) ?
+ LowerBitTable[(val >> 16) & 0xFF] + 16:
+ LowerBitTable[(val >> 24) & 0xFF] + 24;
+
+#else
+
+ if (val & 0xFFFFFFFF)
+ {
+ if (val & 0xFFFF)
+ {
+ return (val & 0xFF) ?
+ LowerBitTable[ val & 0xFF]:
+ LowerBitTable[(val >> 8) & 0xFF] + 8;
+ }
+ return (val & 0xFF0000) ?
+ LowerBitTable[(val >> 16) & 0xFF] + 16:
+ LowerBitTable[(val >> 24) & 0xFF] + 24;
+ }
+ else
+ {
+ if (val & 0xFFFF00000000)
+ {
+ return (val & 0xFF00000000) ?
+ LowerBitTable[(val >> 32) & 0xFF] + 32:
+ LowerBitTable[(val >> 40) & 0xFF] + 40;
+ }
+ return (val & 0xFF000000000000) ?
+ LowerBitTable[(val >> 48) & 0xFF] + 48:
+ LowerBitTable[(val >> 56) & 0xFF] + 56;
+ }
+
+#endif
+}
+
+
+
+// ******* Special (optimized) memory routines
+// Note: null (bad) pointer is not tested
+class MemUtil
+{
+public:
+
+ // Memory compare
+ static int Cmp (const void* p1, const void* p2, UPInt byteCount) { return memcmp(p1, p2, byteCount); }
+ static int Cmp16(const void* p1, const void* p2, UPInt int16Count);
+ static int Cmp32(const void* p1, const void* p2, UPInt int32Count);
+ static int Cmp64(const void* p1, const void* p2, UPInt int64Count);
+};
+
+// ** Inline Implementation
+
+inline int MemUtil::Cmp16(const void* p1, const void* p2, UPInt int16Count)
+{
+ SInt16* pa = (SInt16*)p1;
+ SInt16* pb = (SInt16*)p2;
+ unsigned ic = 0;
+ if (int16Count == 0)
+ return 0;
+ while (pa[ic] == pb[ic])
+ if (++ic==int16Count)
+ return 0;
+ return pa[ic] > pb[ic] ? 1 : -1;
+}
+inline int MemUtil::Cmp32(const void* p1, const void* p2, UPInt int32Count)
+{
+ SInt32* pa = (SInt32*)p1;
+ SInt32* pb = (SInt32*)p2;
+ unsigned ic = 0;
+ if (int32Count == 0)
+ return 0;
+ while (pa[ic] == pb[ic])
+ if (++ic==int32Count)
+ return 0;
+ return pa[ic] > pb[ic] ? 1 : -1;
+}
+inline int MemUtil::Cmp64(const void* p1, const void* p2, UPInt int64Count)
+{
+ SInt64* pa = (SInt64*)p1;
+ SInt64* pb = (SInt64*)p2;
+ unsigned ic = 0;
+ if (int64Count == 0)
+ return 0;
+ while (pa[ic] == pb[ic])
+ if (++ic==int64Count)
+ return 0;
+ return pa[ic] > pb[ic] ? 1 : -1;
+}
+
+// ** End Inline Implementation
+
+
+//-----------------------------------------------------------------------------------
+// ******* Byte Order Conversions
+namespace ByteUtil {
+
+ // *** Swap Byte Order
+
+ // Swap the byte order of a byte array
+ inline void SwapOrder(void* pv, int size)
+ {
+ UByte* pb = (UByte*)pv;
+ UByte temp;
+ for (int i = 0; i < size>>1; i++)
+ {
+ temp = pb[size-1-i];
+ pb[size-1-i] = pb[i];
+ pb[i] = temp;
+ }
+ }
+
+ // Swap the byte order of primitive types
+ inline UByte SwapOrder(UByte v) { return v; }
+ inline SByte SwapOrder(SByte v) { return v; }
+ inline UInt16 SwapOrder(UInt16 v) { return UInt16(v>>8)|UInt16(v<<8); }
+ inline SInt16 SwapOrder(SInt16 v) { return SInt16((UInt16(v)>>8)|(v<<8)); }
+ inline UInt32 SwapOrder(UInt32 v) { return (v>>24)|((v&0x00FF0000)>>8)|((v&0x0000FF00)<<8)|(v<<24); }
+ inline SInt32 SwapOrder(SInt32 p) { return (SInt32)SwapOrder(UInt32(p)); }
+ inline UInt64 SwapOrder(UInt64 v)
+ {
+ return (v>>56) |
+ ((v&UInt64(0x00FF000000000000))>>40) |
+ ((v&UInt64(0x0000FF0000000000))>>24) |
+ ((v&UInt64(0x000000FF00000000))>>8) |
+ ((v&UInt64(0x00000000FF000000))<<8) |
+ ((v&UInt64(0x0000000000FF0000))<<24) |
+ ((v&UInt64(0x000000000000FF00))<<40) |
+ (v<<56);
+ }
+ inline SInt64 SwapOrder(SInt64 v) { return (SInt64)SwapOrder(UInt64(v)); }
+ inline float SwapOrder(float p)
+ {
+ union {
+ float p;
+ UInt32 v;
+ } u;
+ u.p = p;
+ u.v = SwapOrder(u.v);
+ return u.p;
+ }
+
+ inline double SwapOrder(double p)
+ {
+ union {
+ double p;
+ UInt64 v;
+ } u;
+ u.p = p;
+ u.v = SwapOrder(u.v);
+ return u.p;
+ }
+
+ // *** Byte-order conversion
+
+#if (OVR_BYTE_ORDER == OVR_LITTLE_ENDIAN)
+ // Little Endian to System (LE)
+ inline UByte LEToSystem(UByte v) { return v; }
+ inline SByte LEToSystem(SByte v) { return v; }
+ inline UInt16 LEToSystem(UInt16 v) { return v; }
+ inline SInt16 LEToSystem(SInt16 v) { return v; }
+ inline UInt32 LEToSystem(UInt32 v) { return v; }
+ inline SInt32 LEToSystem(SInt32 v) { return v; }
+ inline UInt64 LEToSystem(UInt64 v) { return v; }
+ inline SInt64 LEToSystem(SInt64 v) { return v; }
+ inline float LEToSystem(float v) { return v; }
+ inline double LEToSystem(double v) { return v; }
+
+ // Big Endian to System (LE)
+ inline UByte BEToSystem(UByte v) { return SwapOrder(v); }
+ inline SByte BEToSystem(SByte v) { return SwapOrder(v); }
+ inline UInt16 BEToSystem(UInt16 v) { return SwapOrder(v); }
+ inline SInt16 BEToSystem(SInt16 v) { return SwapOrder(v); }
+ inline UInt32 BEToSystem(UInt32 v) { return SwapOrder(v); }
+ inline SInt32 BEToSystem(SInt32 v) { return SwapOrder(v); }
+ inline UInt64 BEToSystem(UInt64 v) { return SwapOrder(v); }
+ inline SInt64 BEToSystem(SInt64 v) { return SwapOrder(v); }
+ inline float BEToSystem(float v) { return SwapOrder(v); }
+ inline double BEToSystem(double v) { return SwapOrder(v); }
+
+ // System (LE) to Little Endian
+ inline UByte SystemToLE(UByte v) { return v; }
+ inline SByte SystemToLE(SByte v) { return v; }
+ inline UInt16 SystemToLE(UInt16 v) { return v; }
+ inline SInt16 SystemToLE(SInt16 v) { return v; }
+ inline UInt32 SystemToLE(UInt32 v) { return v; }
+ inline SInt32 SystemToLE(SInt32 v) { return v; }
+ inline UInt64 SystemToLE(UInt64 v) { return v; }
+ inline SInt64 SystemToLE(SInt64 v) { return v; }
+ inline float SystemToLE(float v) { return v; }
+ inline double SystemToLE(double v) { return v; }
+
+ // System (LE) to Big Endian
+ inline UByte SystemToBE(UByte v) { return SwapOrder(v); }
+ inline SByte SystemToBE(SByte v) { return SwapOrder(v); }
+ inline UInt16 SystemToBE(UInt16 v) { return SwapOrder(v); }
+ inline SInt16 SystemToBE(SInt16 v) { return SwapOrder(v); }
+ inline UInt32 SystemToBE(UInt32 v) { return SwapOrder(v); }
+ inline SInt32 SystemToBE(SInt32 v) { return SwapOrder(v); }
+ inline UInt64 SystemToBE(UInt64 v) { return SwapOrder(v); }
+ inline SInt64 SystemToBE(SInt64 v) { return SwapOrder(v); }
+ inline float SystemToBE(float v) { return SwapOrder(v); }
+ inline double SystemToBE(double v) { return SwapOrder(v); }
+
+#elif (OVR_BYTE_ORDER == OVR_BIG_ENDIAN)
+ // Little Endian to System (BE)
+ inline UByte LEToSystem(UByte v) { return SwapOrder(v); }
+ inline SByte LEToSystem(SByte v) { return SwapOrder(v); }
+ inline UInt16 LEToSystem(UInt16 v) { return SwapOrder(v); }
+ inline SInt16 LEToSystem(SInt16 v) { return SwapOrder(v); }
+ inline UInt32 LEToSystem(UInt32 v) { return SwapOrder(v); }
+ inline SInt32 LEToSystem(SInt32 v) { return SwapOrder(v); }
+ inline UInt64 LEToSystem(UInt64 v) { return SwapOrder(v); }
+ inline SInt64 LEToSystem(SInt64 v) { return SwapOrder(v); }
+ inline float LEToSystem(float v) { return SwapOrder(v); }
+ inline double LEToSystem(double v) { return SwapOrder(v); }
+
+ // Big Endian to System (BE)
+ inline UByte BEToSystem(UByte v) { return v; }
+ inline SByte BEToSystem(SByte v) { return v; }
+ inline UInt16 BEToSystem(UInt16 v) { return v; }
+ inline SInt16 BEToSystem(SInt16 v) { return v; }
+ inline UInt32 BEToSystem(UInt32 v) { return v; }
+ inline SInt32 BEToSystem(SInt32 v) { return v; }
+ inline UInt64 BEToSystem(UInt64 v) { return v; }
+ inline SInt64 BEToSystem(SInt64 v) { return v; }
+ inline float BEToSystem(float v) { return v; }
+ inline double BEToSystem(double v) { return v; }
+
+ // System (BE) to Little Endian
+ inline UByte SystemToLE(UByte v) { return SwapOrder(v); }
+ inline SByte SystemToLE(SByte v) { return SwapOrder(v); }
+ inline UInt16 SystemToLE(UInt16 v) { return SwapOrder(v); }
+ inline SInt16 SystemToLE(SInt16 v) { return SwapOrder(v); }
+ inline UInt32 SystemToLE(UInt32 v) { return SwapOrder(v); }
+ inline SInt32 SystemToLE(SInt32 v) { return SwapOrder(v); }
+ inline UInt64 SystemToLE(UInt64 v) { return SwapOrder(v); }
+ inline SInt64 SystemToLE(SInt64 v) { return SwapOrder(v); }
+ inline float SystemToLE(float v) { return SwapOrder(v); }
+ inline double SystemToLE(double v) { return SwapOrder(v); }
+
+ // System (BE) to Big Endian
+ inline UByte SystemToBE(UByte v) { return v; }
+ inline SByte SystemToBE(SByte v) { return v; }
+ inline UInt16 SystemToBE(UInt16 v) { return v; }
+ inline SInt16 SystemToBE(SInt16 v) { return v; }
+ inline UInt32 SystemToBE(UInt32 v) { return v; }
+ inline SInt32 SystemToBE(SInt32 v) { return v; }
+ inline UInt64 SystemToBE(UInt64 v) { return v; }
+ inline SInt64 SystemToBE(SInt64 v) { return v; }
+ inline float SystemToBE(float v) { return v; }
+ inline double SystemToBE(double v) { return v; }
+
+#else
+ #error "OVR_BYTE_ORDER must be defined to OVR_LITTLE_ENDIAN or OVR_BIG_ENDIAN"
+#endif
+
+} // namespace ByteUtil
+
+
+
+}} // OVR::Alg
+
+#endif
diff --git a/LibOVR/Src/Kernel/OVR_Allocator.cpp b/LibOVR/Src/Kernel/OVR_Allocator.cpp
index 1f17ffe..ec9a877 100644
--- a/LibOVR/Src/Kernel/OVR_Allocator.cpp
+++ b/LibOVR/Src/Kernel/OVR_Allocator.cpp
@@ -1,84 +1,84 @@
-/************************************************************************************
-
-Filename : OVR_Allocator.cpp
-Content : Installable memory allocator implementation
-Created : September 19, 2012
-Notes :
-
-Copyright : Copyright 2012 Oculus VR, Inc. All Rights reserved.
-
-Use of this software is subject to the terms of the Oculus license
-agreement provided at the time of installation or download, or which
-otherwise accompanies this software in either electronic or hard copy form.
-
-************************************************************************************/
-
-#include "OVR_Allocator.h"
-#ifdef OVR_OS_MAC
- #include <stdlib.h>
-#else
- #include <malloc.h>
-#endif
-
-namespace OVR {
-
-//-----------------------------------------------------------------------------------
-// ***** Allocator
-
-Allocator* Allocator::pInstance = 0;
-
-// Default AlignedAlloc implementation will delegate to Alloc/Free after doing rounding.
-void* Allocator::AllocAligned(UPInt size, UPInt align)
-{
- OVR_ASSERT((align & (align-1)) == 0);
- align = (align > sizeof(UPInt)) ? align : sizeof(UPInt);
- UPInt p = (UPInt)Alloc(size+align);
- UPInt aligned = 0;
- if (p)
- {
- aligned = (UPInt(p) + align-1) & ~(align-1);
- if (aligned == p)
- aligned += align;
- *(((UPInt*)aligned)-1) = aligned-p;
- }
- return (void*)aligned;
-}
-
-void Allocator::FreeAligned(void* p)
-{
- UPInt src = UPInt(p) - *(((UPInt*)p)-1);
- Free((void*)src);
-}
-
-
-//------------------------------------------------------------------------
-// ***** Default Allocator
-
-// This allocator is created and used if no other allocator is installed.
-// Default allocator delegates to system malloc.
-
-void* DefaultAllocator::Alloc(UPInt size)
-{
- return malloc(size);
-}
-void* DefaultAllocator::AllocDebug(UPInt size, const char* file, unsigned line)
-{
-#if defined(OVR_CC_MSVC) && defined(_CRTDBG_MAP_ALLOC)
- return _malloc_dbg(size, _NORMAL_BLOCK, file, line);
-#else
- OVR_UNUSED2(file, line);
- return malloc(size);
-#endif
-}
-
-void* DefaultAllocator::Realloc(void* p, UPInt newSize)
-{
- return realloc(p, newSize);
-}
-void DefaultAllocator::Free(void *p)
-{
- return free(p);
-}
-
-
-} // OVR
+/************************************************************************************
+
+Filename : OVR_Allocator.cpp
+Content : Installable memory allocator implementation
+Created : September 19, 2012
+Notes :
+
+Copyright : Copyright 2012 Oculus VR, Inc. All Rights reserved.
+
+Use of this software is subject to the terms of the Oculus license
+agreement provided at the time of installation or download, or which
+otherwise accompanies this software in either electronic or hard copy form.
+
+************************************************************************************/
+
+#include "OVR_Allocator.h"
+#ifdef OVR_OS_MAC
+ #include <stdlib.h>
+#else
+ #include <malloc.h>
+#endif
+
+namespace OVR {
+
+//-----------------------------------------------------------------------------------
+// ***** Allocator
+
+Allocator* Allocator::pInstance = 0;
+
+// Default AlignedAlloc implementation will delegate to Alloc/Free after doing rounding.
+void* Allocator::AllocAligned(UPInt size, UPInt align)
+{
+ OVR_ASSERT((align & (align-1)) == 0);
+ align = (align > sizeof(UPInt)) ? align : sizeof(UPInt);
+ UPInt p = (UPInt)Alloc(size+align);
+ UPInt aligned = 0;
+ if (p)
+ {
+ aligned = (UPInt(p) + align-1) & ~(align-1);
+ if (aligned == p)
+ aligned += align;
+ *(((UPInt*)aligned)-1) = aligned-p;
+ }
+ return (void*)aligned;
+}
+
+void Allocator::FreeAligned(void* p)
+{
+ UPInt src = UPInt(p) - *(((UPInt*)p)-1);
+ Free((void*)src);
+}
+
+
+//------------------------------------------------------------------------
+// ***** Default Allocator
+
+// This allocator is created and used if no other allocator is installed.
+// Default allocator delegates to system malloc.
+
+void* DefaultAllocator::Alloc(UPInt size)
+{
+ return malloc(size);
+}
+void* DefaultAllocator::AllocDebug(UPInt size, const char* file, unsigned line)
+{
+#if defined(OVR_CC_MSVC) && defined(_CRTDBG_MAP_ALLOC)
+ return _malloc_dbg(size, _NORMAL_BLOCK, file, line);
+#else
+ OVR_UNUSED2(file, line);
+ return malloc(size);
+#endif
+}
+
+void* DefaultAllocator::Realloc(void* p, UPInt newSize)
+{
+ return realloc(p, newSize);
+}
+void DefaultAllocator::Free(void *p)
+{
+ return free(p);
+}
+
+
+} // OVR
diff --git a/LibOVR/Src/Kernel/OVR_Allocator.h b/LibOVR/Src/Kernel/OVR_Allocator.h
index 88cbb42..6625206 100644
--- a/LibOVR/Src/Kernel/OVR_Allocator.h
+++ b/LibOVR/Src/Kernel/OVR_Allocator.h
@@ -1,336 +1,336 @@
-/************************************************************************************
-
-PublicHeader: OVR.h
-Filename : OVR_Allocator.h
-Content : Installable memory allocator
-Created : September 19, 2012
-Notes :
-
-Copyright : Copyright 2012 Oculus VR, Inc. All Rights reserved.
-
-Use of this software is subject to the terms of the Oculus license
-agreement provided at the time of installation or download, or which
-otherwise accompanies this software in either electronic or hard copy form.
-
-************************************************************************************/
-
-#ifndef OVR_Allocator_h
-#define OVR_Allocator_h
-
-#include "OVR_Types.h"
-
-//-----------------------------------------------------------------------------------
-
-// ***** Disable template-unfriendly MS VC++ warnings
-#if defined(OVR_CC_MSVC)
-// Pragma to prevent long name warnings in in VC++
-#pragma warning(disable : 4503)
-#pragma warning(disable : 4786)
-// In MSVC 7.1, warning about placement new POD default initializer
-#pragma warning(disable : 4345)
-#endif
-
-// Un-define new so that placement constructors work
-#undef new
-
-
-//-----------------------------------------------------------------------------------
-// ***** Placement new overrides
-
-// Calls constructor on own memory created with "new(ptr) type"
-#ifndef __PLACEMENT_NEW_INLINE
-#define __PLACEMENT_NEW_INLINE
-
-# if defined(OVR_CC_MWERKS) || defined(OVR_CC_BORLAND) || defined(OVR_CC_GNU)
-# include <new>
-# else
- // Useful on MSVC
- OVR_FORCE_INLINE void* operator new (OVR::UPInt n, void *ptr) { OVR_UNUSED(n); return ptr; }
- OVR_FORCE_INLINE void operator delete (void *, void *) { }
-# endif
-
-#endif // __PLACEMENT_NEW_INLINE
-
-
-
-//------------------------------------------------------------------------
-// ***** Macros to redefine class new/delete operators
-
-// Types specifically declared to allow disambiguation of address in
-// class member operator new.
-
-#define OVR_MEMORY_REDEFINE_NEW_IMPL(class_name, check_delete) \
- void* operator new(UPInt sz) \
- { void *p = OVR_ALLOC_DEBUG(sz, __FILE__, __LINE__); return p; } \
- void* operator new(UPInt sz, const char* file, int line) \
- { void* p = OVR_ALLOC_DEBUG(sz, file, line); OVR_UNUSED2(file, line); return p; } \
- void operator delete(void *p) \
- { check_delete(class_name, p); OVR_FREE(p); } \
- void operator delete(void *p, const char*, int) \
- { check_delete(class_name, p); OVR_FREE(p); }
-
-#define OVR_MEMORY_DEFINE_PLACEMENT_NEW \
- void* operator new (UPInt n, void *ptr) { OVR_UNUSED(n); return ptr; } \
- void operator delete (void *ptr, void *ptr2) { OVR_UNUSED2(ptr,ptr2); }
-
-
-#define OVR_MEMORY_CHECK_DELETE_NONE(class_name, p)
-
-// Redefined all delete/new operators in a class without custom memory initialization
-#define OVR_MEMORY_REDEFINE_NEW(class_name) \
- OVR_MEMORY_REDEFINE_NEW_IMPL(class_name, OVR_MEMORY_CHECK_DELETE_NONE)
-
-
-namespace OVR {
-
-//-----------------------------------------------------------------------------------
-// ***** Construct / Destruct
-
-// Construct/Destruct functions are useful when new is redefined, as they can
-// be called instead of placement new constructors.
-
-
-template <class T>
-OVR_FORCE_INLINE T* Construct(void *p)
-{
- return ::new(p) T;
-}
-
-template <class T>
-OVR_FORCE_INLINE T* Construct(void *p, const T& source)
-{
- return ::new(p) T(source);
-}
-
-// Same as above, but allows for a different type of constructor.
-template <class T, class S>
-OVR_FORCE_INLINE T* ConstructAlt(void *p, const S& source)
-{
- return ::new(p) T(source);
-}
-
-template <class T, class S1, class S2>
-OVR_FORCE_INLINE T* ConstructAlt(void *p, const S1& src1, const S2& src2)
-{
- return ::new(p) T(src1, src2);
-}
-
-template <class T>
-OVR_FORCE_INLINE void ConstructArray(void *p, UPInt count)
-{
- UByte *pdata = (UByte*)p;
- for (UPInt i=0; i< count; ++i, pdata += sizeof(T))
- {
- Construct<T>(pdata);
- }
-}
-
-template <class T>
-OVR_FORCE_INLINE void ConstructArray(void *p, UPInt count, const T& source)
-{
- UByte *pdata = (UByte*)p;
- for (UPInt i=0; i< count; ++i, pdata += sizeof(T))
- {
- Construct<T>(pdata, source);
- }
-}
-
-template <class T>
-OVR_FORCE_INLINE void Destruct(T *pobj)
-{
- pobj->~T();
- OVR_UNUSED1(pobj); // Fix incorrect 'unused variable' MSVC warning.
-}
-
-template <class T>
-OVR_FORCE_INLINE void DestructArray(T *pobj, UPInt count)
-{
- for (UPInt i=0; i<count; ++i, ++pobj)
- pobj->~T();
-}
-
-
-//-----------------------------------------------------------------------------------
-// ***** Allocator
-
-// Allocator defines a memory allocation interface that developers can override
-// to to provide memory for OVR; an instance of this class is typically created on
-// application startup and passed into System or OVR::System constructor.
-//
-//
-// Users implementing this interface must provide three functions: Alloc, Free,
-// and Realloc. Implementations of these functions must honor the requested alignment.
-// Although arbitrary alignment requests are possible, requested alignment will
-// typically be small, such as 16 bytes or less.
-
-class Allocator
-{
- friend class System;
-public:
-
- // *** Standard Alignment Alloc/Free
-
- // Allocate memory of specified size with default alignment.
- // Alloc of size==0 will allocate a tiny block & return a valid pointer;
- // this makes it suitable for new operator.
- virtual void* Alloc(UPInt size) = 0;
- // Same as Alloc, but provides an option of passing debug data.
- virtual void* AllocDebug(UPInt size, const char* file, unsigned line)
- { OVR_UNUSED2(file, line); return Alloc(size); }
-
- // Reallocate memory block to a new size, copying data if necessary. Returns the pointer to
- // new memory block, which may be the same as original pointer. Will return 0 if reallocation
- // failed, in which case previous memory is still valid.
- // Realloc to decrease size will never fail.
- // Realloc of pointer == 0 is equivalent to Alloc
- // Realloc to size == 0, shrinks to the minimal size, pointer remains valid and requires Free().
- virtual void* Realloc(void* p, UPInt newSize) = 0;
-
- // Frees memory allocated by Alloc/Realloc.
- // Free of null pointer is valid and will do nothing.
- virtual void Free(void *p) = 0;
-
-
- // *** Standard Alignment Alloc/Free
-
- // Allocate memory of specified alignment.
- // Memory allocated with AllocAligned MUST be freed with FreeAligned.
- // Default implementation will delegate to Alloc/Free after doing rounding.
- virtual void* AllocAligned(UPInt size, UPInt align);
- // Frees memory allocated with AllocAligned.
- virtual void FreeAligned(void* p);
-
- // Returns the pointer to the current globally installed Allocator instance.
- // This pointer is used for most of the memory allocations.
- static Allocator* GetInstance() { return pInstance; }
-
-
-protected:
- // onSystemShutdown is called on the allocator during System::Shutdown.
- // At this point, all allocations should've been freed.
- virtual void onSystemShutdown() { }
-
-public:
- static void setInstance(Allocator* palloc)
- {
- OVR_ASSERT((pInstance == 0) || (palloc == 0));
- pInstance = palloc;
- }
-
-private:
-
- static Allocator* pInstance;
-};
-
-
-
-//------------------------------------------------------------------------
-// ***** Allocator_SingletonSupport
-
-// Allocator_SingletonSupport is a Allocator wrapper class that implements
-// the InitSystemSingleton static function, used to create a global singleton
-// used for the OVR::System default argument initialization.
-//
-// End users implementing custom Allocator interface don't need to make use of this base
-// class; they can just create an instance of their own class on stack and pass it to System.
-
-template<class D>
-class Allocator_SingletonSupport : public Allocator
-{
- struct AllocContainer
- {
- UPInt Data[(sizeof(D) + sizeof(UPInt)-1) / sizeof(UPInt)];
- bool Initialized;
- AllocContainer() : Initialized(0) { }
- };
-
- AllocContainer* pContainer;
-
-public:
- Allocator_SingletonSupport() : pContainer(0) { }
-
- // Creates a singleton instance of this Allocator class used
- // on OVR_DEFAULT_ALLOCATOR during System initialization.
- static D* InitSystemSingleton()
- {
- static AllocContainer Container;
- OVR_ASSERT(Container.Initialized == false);
-
- Allocator_SingletonSupport<D> *presult = Construct<D>((void*)Container.Data);
- presult->pContainer = &Container;
- Container.Initialized = true;
- return (D*)presult;
- }
-
-protected:
- virtual void onSystemShutdown()
- {
- Allocator::onSystemShutdown();
- if (pContainer)
- {
- pContainer->Initialized = false;
- Destruct((D*)this);
- pContainer = 0;
- }
- }
-};
-
-//------------------------------------------------------------------------
-// ***** Default Allocator
-
-// This allocator is created and used if no other allocator is installed.
-// Default allocator delegates to system malloc.
-
-class DefaultAllocator : public Allocator_SingletonSupport<DefaultAllocator>
-{
-public:
- virtual void* Alloc(UPInt size);
- virtual void* AllocDebug(UPInt size, const char* file, unsigned line);
- virtual void* Realloc(void* p, UPInt newSize);
- virtual void Free(void *p);
-};
-
-
-//------------------------------------------------------------------------
-// ***** Memory Allocation Macros
-
-// These macros should be used for global allocation. In the future, these
-// macros will allows allocation to be extended with debug file/line information
-// if necessary.
-
-#define OVR_REALLOC(p,s) OVR::Allocator::GetInstance()->Realloc((p),(s))
-#define OVR_FREE(p) OVR::Allocator::GetInstance()->Free((p))
-#define OVR_ALLOC_ALIGNED(s,a) OVR::Allocator::GetInstance()->AllocAligned((s),(a))
-#define OVR_FREE_ALIGNED(p) OVR::Allocator::GetInstance()->FreeAligned((p))
-
-#ifdef OVR_BUILD_DEBUG
-#define OVR_ALLOC(s) OVR::Allocator::GetInstance()->AllocDebug((s), __FILE__, __LINE__)
-#define OVR_ALLOC_DEBUG(s,f,l) OVR::Allocator::GetInstance()->AllocDebug((s), f, l)
-#else
-#define OVR_ALLOC(s) OVR::Allocator::GetInstance()->Alloc((s))
-#define OVR_ALLOC_DEBUG(s,f,l) OVR::Allocator::GetInstance()->Alloc((s))
-#endif
-
-//------------------------------------------------------------------------
-
-// Base class that overrides the new and delete operators.
-// Deriving from this class, even as a multiple base, incurs no space overhead.
-class NewOverrideBase
-{
-public:
-
- // Redefine all new & delete operators.
- OVR_MEMORY_REDEFINE_NEW(NewOverrideBase)
-};
-
-
-} // OVR
-
-
-// Redefine operator 'new' if necessary.
-#if defined(OVR_DEFINE_NEW)
-#define new OVR_DEFINE_NEW
-#endif
-
-
-#endif // OVR_Memory
+/************************************************************************************
+
+PublicHeader: OVR.h
+Filename : OVR_Allocator.h
+Content : Installable memory allocator
+Created : September 19, 2012
+Notes :
+
+Copyright : Copyright 2012 Oculus VR, Inc. All Rights reserved.
+
+Use of this software is subject to the terms of the Oculus license
+agreement provided at the time of installation or download, or which
+otherwise accompanies this software in either electronic or hard copy form.
+
+************************************************************************************/
+
+#ifndef OVR_Allocator_h
+#define OVR_Allocator_h
+
+#include "OVR_Types.h"
+
+//-----------------------------------------------------------------------------------
+
+// ***** Disable template-unfriendly MS VC++ warnings
+#if defined(OVR_CC_MSVC)
+// Pragma to prevent long name warnings in in VC++
+#pragma warning(disable : 4503)
+#pragma warning(disable : 4786)
+// In MSVC 7.1, warning about placement new POD default initializer
+#pragma warning(disable : 4345)
+#endif
+
+// Un-define new so that placement constructors work
+#undef new
+
+
+//-----------------------------------------------------------------------------------
+// ***** Placement new overrides
+
+// Calls constructor on own memory created with "new(ptr) type"
+#ifndef __PLACEMENT_NEW_INLINE
+#define __PLACEMENT_NEW_INLINE
+
+# if defined(OVR_CC_MWERKS) || defined(OVR_CC_BORLAND) || defined(OVR_CC_GNU)
+# include <new>
+# else
+ // Useful on MSVC
+ OVR_FORCE_INLINE void* operator new (OVR::UPInt n, void *ptr) { OVR_UNUSED(n); return ptr; }
+ OVR_FORCE_INLINE void operator delete (void *, void *) { }
+# endif
+
+#endif // __PLACEMENT_NEW_INLINE
+
+
+
+//------------------------------------------------------------------------
+// ***** Macros to redefine class new/delete operators
+
+// Types specifically declared to allow disambiguation of address in
+// class member operator new.
+
+#define OVR_MEMORY_REDEFINE_NEW_IMPL(class_name, check_delete) \
+ void* operator new(UPInt sz) \
+ { void *p = OVR_ALLOC_DEBUG(sz, __FILE__, __LINE__); return p; } \
+ void* operator new(UPInt sz, const char* file, int line) \
+ { void* p = OVR_ALLOC_DEBUG(sz, file, line); OVR_UNUSED2(file, line); return p; } \
+ void operator delete(void *p) \
+ { check_delete(class_name, p); OVR_FREE(p); } \
+ void operator delete(void *p, const char*, int) \
+ { check_delete(class_name, p); OVR_FREE(p); }
+
+#define OVR_MEMORY_DEFINE_PLACEMENT_NEW \
+ void* operator new (UPInt n, void *ptr) { OVR_UNUSED(n); return ptr; } \
+ void operator delete (void *ptr, void *ptr2) { OVR_UNUSED2(ptr,ptr2); }
+
+
+#define OVR_MEMORY_CHECK_DELETE_NONE(class_name, p)
+
+// Redefined all delete/new operators in a class without custom memory initialization
+#define OVR_MEMORY_REDEFINE_NEW(class_name) \
+ OVR_MEMORY_REDEFINE_NEW_IMPL(class_name, OVR_MEMORY_CHECK_DELETE_NONE)
+
+
+namespace OVR {
+
+//-----------------------------------------------------------------------------------
+// ***** Construct / Destruct
+
+// Construct/Destruct functions are useful when new is redefined, as they can
+// be called instead of placement new constructors.
+
+
+template <class T>
+OVR_FORCE_INLINE T* Construct(void *p)
+{
+ return ::new(p) T;
+}
+
+template <class T>
+OVR_FORCE_INLINE T* Construct(void *p, const T& source)
+{
+ return ::new(p) T(source);
+}
+
+// Same as above, but allows for a different type of constructor.
+template <class T, class S>
+OVR_FORCE_INLINE T* ConstructAlt(void *p, const S& source)
+{
+ return ::new(p) T(source);
+}
+
+template <class T, class S1, class S2>
+OVR_FORCE_INLINE T* ConstructAlt(void *p, const S1& src1, const S2& src2)
+{
+ return ::new(p) T(src1, src2);
+}
+
+template <class T>
+OVR_FORCE_INLINE void ConstructArray(void *p, UPInt count)
+{
+ UByte *pdata = (UByte*)p;
+ for (UPInt i=0; i< count; ++i, pdata += sizeof(T))
+ {
+ Construct<T>(pdata);
+ }
+}
+
+template <class T>
+OVR_FORCE_INLINE void ConstructArray(void *p, UPInt count, const T& source)
+{
+ UByte *pdata = (UByte*)p;
+ for (UPInt i=0; i< count; ++i, pdata += sizeof(T))
+ {
+ Construct<T>(pdata, source);
+ }
+}
+
+template <class T>
+OVR_FORCE_INLINE void Destruct(T *pobj)
+{
+ pobj->~T();
+ OVR_UNUSED1(pobj); // Fix incorrect 'unused variable' MSVC warning.
+}
+
+template <class T>
+OVR_FORCE_INLINE void DestructArray(T *pobj, UPInt count)
+{
+ for (UPInt i=0; i<count; ++i, ++pobj)
+ pobj->~T();
+}
+
+
+//-----------------------------------------------------------------------------------
+// ***** Allocator
+
+// Allocator defines a memory allocation interface that developers can override
+// to to provide memory for OVR; an instance of this class is typically created on
+// application startup and passed into System or OVR::System constructor.
+//
+//
+// Users implementing this interface must provide three functions: Alloc, Free,
+// and Realloc. Implementations of these functions must honor the requested alignment.
+// Although arbitrary alignment requests are possible, requested alignment will
+// typically be small, such as 16 bytes or less.
+
+class Allocator
+{
+ friend class System;
+public:
+
+ // *** Standard Alignment Alloc/Free
+
+ // Allocate memory of specified size with default alignment.
+ // Alloc of size==0 will allocate a tiny block & return a valid pointer;
+ // this makes it suitable for new operator.
+ virtual void* Alloc(UPInt size) = 0;
+ // Same as Alloc, but provides an option of passing debug data.
+ virtual void* AllocDebug(UPInt size, const char* file, unsigned line)
+ { OVR_UNUSED2(file, line); return Alloc(size); }
+
+ // Reallocate memory block to a new size, copying data if necessary. Returns the pointer to
+ // new memory block, which may be the same as original pointer. Will return 0 if reallocation
+ // failed, in which case previous memory is still valid.
+ // Realloc to decrease size will never fail.
+ // Realloc of pointer == 0 is equivalent to Alloc
+ // Realloc to size == 0, shrinks to the minimal size, pointer remains valid and requires Free().
+ virtual void* Realloc(void* p, UPInt newSize) = 0;
+
+ // Frees memory allocated by Alloc/Realloc.
+ // Free of null pointer is valid and will do nothing.
+ virtual void Free(void *p) = 0;
+
+
+ // *** Standard Alignment Alloc/Free
+
+ // Allocate memory of specified alignment.
+ // Memory allocated with AllocAligned MUST be freed with FreeAligned.
+ // Default implementation will delegate to Alloc/Free after doing rounding.
+ virtual void* AllocAligned(UPInt size, UPInt align);
+ // Frees memory allocated with AllocAligned.
+ virtual void FreeAligned(void* p);
+
+ // Returns the pointer to the current globally installed Allocator instance.
+ // This pointer is used for most of the memory allocations.
+ static Allocator* GetInstance() { return pInstance; }
+
+
+protected:
+ // onSystemShutdown is called on the allocator during System::Shutdown.
+ // At this point, all allocations should've been freed.
+ virtual void onSystemShutdown() { }
+
+public:
+ static void setInstance(Allocator* palloc)
+ {
+ OVR_ASSERT((pInstance == 0) || (palloc == 0));
+ pInstance = palloc;
+ }
+
+private:
+
+ static Allocator* pInstance;
+};
+
+
+
+//------------------------------------------------------------------------
+// ***** Allocator_SingletonSupport
+
+// Allocator_SingletonSupport is a Allocator wrapper class that implements
+// the InitSystemSingleton static function, used to create a global singleton
+// used for the OVR::System default argument initialization.
+//
+// End users implementing custom Allocator interface don't need to make use of this base
+// class; they can just create an instance of their own class on stack and pass it to System.
+
+template<class D>
+class Allocator_SingletonSupport : public Allocator
+{
+ struct AllocContainer
+ {
+ UPInt Data[(sizeof(D) + sizeof(UPInt)-1) / sizeof(UPInt)];
+ bool Initialized;
+ AllocContainer() : Initialized(0) { }
+ };
+
+ AllocContainer* pContainer;
+
+public:
+ Allocator_SingletonSupport() : pContainer(0) { }
+
+ // Creates a singleton instance of this Allocator class used
+ // on OVR_DEFAULT_ALLOCATOR during System initialization.
+ static D* InitSystemSingleton()
+ {
+ static AllocContainer Container;
+ OVR_ASSERT(Container.Initialized == false);
+
+ Allocator_SingletonSupport<D> *presult = Construct<D>((void*)Container.Data);
+ presult->pContainer = &Container;
+ Container.Initialized = true;
+ return (D*)presult;
+ }
+
+protected:
+ virtual void onSystemShutdown()
+ {
+ Allocator::onSystemShutdown();
+ if (pContainer)
+ {
+ pContainer->Initialized = false;
+ Destruct((D*)this);
+ pContainer = 0;
+ }
+ }
+};
+
+//------------------------------------------------------------------------
+// ***** Default Allocator
+
+// This allocator is created and used if no other allocator is installed.
+// Default allocator delegates to system malloc.
+
+class DefaultAllocator : public Allocator_SingletonSupport<DefaultAllocator>
+{
+public:
+ virtual void* Alloc(UPInt size);
+ virtual void* AllocDebug(UPInt size, const char* file, unsigned line);
+ virtual void* Realloc(void* p, UPInt newSize);
+ virtual void Free(void *p);
+};
+
+
+//------------------------------------------------------------------------
+// ***** Memory Allocation Macros
+
+// These macros should be used for global allocation. In the future, these
+// macros will allows allocation to be extended with debug file/line information
+// if necessary.
+
+#define OVR_REALLOC(p,s) OVR::Allocator::GetInstance()->Realloc((p),(s))
+#define OVR_FREE(p) OVR::Allocator::GetInstance()->Free((p))
+#define OVR_ALLOC_ALIGNED(s,a) OVR::Allocator::GetInstance()->AllocAligned((s),(a))
+#define OVR_FREE_ALIGNED(p) OVR::Allocator::GetInstance()->FreeAligned((p))
+
+#ifdef OVR_BUILD_DEBUG
+#define OVR_ALLOC(s) OVR::Allocator::GetInstance()->AllocDebug((s), __FILE__, __LINE__)
+#define OVR_ALLOC_DEBUG(s,f,l) OVR::Allocator::GetInstance()->AllocDebug((s), f, l)
+#else
+#define OVR_ALLOC(s) OVR::Allocator::GetInstance()->Alloc((s))
+#define OVR_ALLOC_DEBUG(s,f,l) OVR::Allocator::GetInstance()->Alloc((s))
+#endif
+
+//------------------------------------------------------------------------
+
+// Base class that overrides the new and delete operators.
+// Deriving from this class, even as a multiple base, incurs no space overhead.
+class NewOverrideBase
+{
+public:
+
+ // Redefine all new & delete operators.
+ OVR_MEMORY_REDEFINE_NEW(NewOverrideBase)
+};
+
+
+} // OVR
+
+
+// Redefine operator 'new' if necessary.
+#if defined(OVR_DEFINE_NEW)
+#define new OVR_DEFINE_NEW
+#endif
+
+
+#endif // OVR_Memory
diff --git a/LibOVR/Src/Kernel/OVR_Array.h b/LibOVR/Src/Kernel/OVR_Array.h
index 905d58f..7877fb9 100644
--- a/LibOVR/Src/Kernel/OVR_Array.h
+++ b/LibOVR/Src/Kernel/OVR_Array.h
@@ -1,793 +1,793 @@
-/************************************************************************************
-
-PublicHeader: OVR.h
-Filename : OVR_Array.h
-Content : Template implementation for Array
-Created : September 19, 2012
-Notes :
-
-Copyright : Copyright 2012 Oculus VR, Inc. All Rights reserved.
-
-Use of this software is subject to the terms of the Oculus license
-agreement provided at the time of installation or download, or which
-otherwise accompanies this software in either electronic or hard copy form.
-
-************************************************************************************/
-
-#ifndef OVR_Array_h
-#define OVR_Array_h
-
-#include "OVR_ContainerAllocator.h"
-
-namespace OVR {
-
-//-----------------------------------------------------------------------------------
-// ***** ArrayDefaultPolicy
-//
-// Default resize behavior. No minimal capacity, Granularity=4,
-// Shrinking as needed. ArrayConstPolicy actually is the same as
-// ArrayDefaultPolicy, but parametrized with constants.
-// This struct is used only in order to reduce the template "matroska".
-struct ArrayDefaultPolicy
-{
- ArrayDefaultPolicy() : Capacity(0) {}
- ArrayDefaultPolicy(const ArrayDefaultPolicy&) : Capacity(0) {}
-
- UPInt GetMinCapacity() const { return 0; }
- UPInt GetGranularity() const { return 4; }
- bool NeverShrinking() const { return 0; }
-
- UPInt GetCapacity() const { return Capacity; }
- void SetCapacity(UPInt capacity) { Capacity = capacity; }
-private:
- UPInt Capacity;
-};
-
-
-//-----------------------------------------------------------------------------------
-// ***** ArrayConstPolicy
-//
-// Statically parametrized resizing behavior:
-// MinCapacity, Granularity, and Shrinking flag.
-template<int MinCapacity=0, int Granularity=4, bool NeverShrink=false>
-struct ArrayConstPolicy
-{
- typedef ArrayConstPolicy<MinCapacity, Granularity, NeverShrink> SelfType;
-
- ArrayConstPolicy() : Capacity(0) {}
- ArrayConstPolicy(const SelfType&) : Capacity(0) {}
-
- UPInt GetMinCapacity() const { return MinCapacity; }
- UPInt GetGranularity() const { return Granularity; }
- bool NeverShrinking() const { return NeverShrink; }
-
- UPInt GetCapacity() const { return Capacity; }
- void SetCapacity(UPInt capacity) { Capacity = capacity; }
-private:
- UPInt Capacity;
-};
-
-//-----------------------------------------------------------------------------------
-// ***** ArrayDataBase
-//
-// Basic operations with array data: Reserve, Resize, Free, ArrayPolicy.
-// For internal use only: ArrayData,ArrayDataCC and others.
-template<class T, class Allocator, class SizePolicy>
-struct ArrayDataBase
-{
- typedef T ValueType;
- typedef Allocator AllocatorType;
- typedef SizePolicy SizePolicyType;
- typedef ArrayDataBase<T, Allocator, SizePolicy> SelfType;
-
- ArrayDataBase()
- : Data(0), Size(0), Policy() {}
-
- ArrayDataBase(const SizePolicy& p)
- : Data(0), Size(0), Policy(p) {}
-
- ~ArrayDataBase()
- {
- Allocator::DestructArray(Data, Size);
- Allocator::Free(Data);
- }
-
- UPInt GetCapacity() const
- {
- return Policy.GetCapacity();
- }
-
- void ClearAndRelease()
- {
- Allocator::DestructArray(Data, Size);
- Allocator::Free(Data);
- Data = 0;
- Size = 0;
- Policy.SetCapacity(0);
- }
-
- void Reserve(UPInt newCapacity)
- {
- if (Policy.NeverShrinking() && newCapacity < GetCapacity())
- return;
-
- if (newCapacity < Policy.GetMinCapacity())
- newCapacity = Policy.GetMinCapacity();
-
- // Resize the buffer.
- if (newCapacity == 0)
- {
- if (Data)
- {
- Allocator::Free(Data);
- Data = 0;
- }
- Policy.SetCapacity(0);
- }
- else
- {
- UPInt gran = Policy.GetGranularity();
- newCapacity = (newCapacity + gran - 1) / gran * gran;
- if (Data)
- {
- if (Allocator::IsMovable())
- {
- Data = (T*)Allocator::Realloc(Data, sizeof(T) * newCapacity);
- }
- else
- {
- T* newData = (T*)Allocator::Alloc(sizeof(T) * newCapacity);
- UPInt i, s;
- s = (Size < newCapacity) ? Size : newCapacity;
- for (i = 0; i < s; ++i)
- {
- Allocator::Construct(&newData[i], Data[i]);
- Allocator::Destruct(&Data[i]);
- }
- for (i = s; i < Size; ++i)
- {
- Allocator::Destruct(&Data[i]);
- }
- Allocator::Free(Data);
- Data = newData;
- }
- }
- else
- {
- Data = (T*)Allocator::Alloc(sizeof(T) * newCapacity);
- //memset(Buffer, 0, (sizeof(ValueType) * newSize)); // Do we need this?
- }
- Policy.SetCapacity(newCapacity);
- // OVR_ASSERT(Data); // need to throw (or something) on alloc failure!
- }
- }
-
- // This version of Resize DOES NOT construct the elements.
- // It's done to optimize PushBack, which uses a copy constructor
- // instead of the default constructor and assignment
- void ResizeNoConstruct(UPInt newSize)
- {
- UPInt oldSize = Size;
-
- if (newSize < oldSize)
- {
- Allocator::DestructArray(Data + newSize, oldSize - newSize);
- if (newSize < (Policy.GetCapacity() >> 1))
- {
- Reserve(newSize);
- }
- }
- else if(newSize >= Policy.GetCapacity())
- {
- Reserve(newSize + (newSize >> 2));
- }
- //! IMPORTANT to modify Size only after Reserve completes, because garbage collectable
- // array may use this array and may traverse it during Reserve (in the case, if
- // collection occurs because of heap limit exceeded).
- Size = newSize;
- }
-
- ValueType* Data;
- UPInt Size;
- SizePolicy Policy;
-};
-
-
-
-//-----------------------------------------------------------------------------------
-// ***** ArrayData
-//
-// General purpose array data.
-// For internal use only in Array, ArrayLH, ArrayPOD and so on.
-template<class T, class Allocator, class SizePolicy>
-struct ArrayData : ArrayDataBase<T, Allocator, SizePolicy>
-{
- typedef T ValueType;
- typedef Allocator AllocatorType;
- typedef SizePolicy SizePolicyType;
- typedef ArrayDataBase<T, Allocator, SizePolicy> BaseType;
- typedef ArrayData <T, Allocator, SizePolicy> SelfType;
-
- ArrayData()
- : BaseType() { }
-
- ArrayData(int size)
- : BaseType() { Resize(size); }
-
- ArrayData(const SelfType& a)
- : BaseType(a.Policy) { Append(a.Data, a.Size); }
-
-
- void Resize(UPInt newSize)
- {
- UPInt oldSize = this->Size;
- BaseType::ResizeNoConstruct(newSize);
- if(newSize > oldSize)
- Allocator::ConstructArray(this->Data + oldSize, newSize - oldSize);
- }
-
- void PushBack(const ValueType& val)
- {
- BaseType::ResizeNoConstruct(this->Size + 1);
- Allocator::Construct(this->Data + this->Size - 1, val);
- }
-
- template<class S>
- void PushBackAlt(const S& val)
- {
- BaseType::ResizeNoConstruct(this->Size + 1);
- Allocator::ConstructAlt(this->Data + this->Size - 1, val);
- }
-
- // Append the given data to the array.
- void Append(const ValueType other[], UPInt count)
- {
- if (count)
- {
- UPInt oldSize = this->Size;
- BaseType::ResizeNoConstruct(this->Size + count);
- Allocator::ConstructArray(this->Data + oldSize, count, other);
- }
- }
-};
-
-
-
-//-----------------------------------------------------------------------------------
-// ***** ArrayDataCC
-//
-// A modification of ArrayData that always copy-constructs new elements
-// using a specified DefaultValue. For internal use only in ArrayCC.
-template<class T, class Allocator, class SizePolicy>
-struct ArrayDataCC : ArrayDataBase<T, Allocator, SizePolicy>
-{
- typedef T ValueType;
- typedef Allocator AllocatorType;
- typedef SizePolicy SizePolicyType;
- typedef ArrayDataBase<T, Allocator, SizePolicy> BaseType;
- typedef ArrayDataCC <T, Allocator, SizePolicy> SelfType;
-
- ArrayDataCC(const ValueType& defval)
- : BaseType(), DefaultValue(defval) { }
-
- ArrayDataCC(const ValueType& defval, int size)
- : BaseType(), DefaultValue(defval) { Resize(size); }
-
- ArrayDataCC(const SelfType& a)
- : BaseType(a.Policy), DefaultValue(a.DefaultValue) { Append(a.Data, a.Size); }
-
-
- void Resize(UPInt newSize)
- {
- UPInt oldSize = this->Size;
- BaseType::ResizeNoConstruct(newSize);
- if(newSize > oldSize)
- Allocator::ConstructArray(this->Data + oldSize, newSize - oldSize, DefaultValue);
- }
-
- void PushBack(const ValueType& val)
- {
- BaseType::ResizeNoConstruct(this->Size + 1);
- Allocator::Construct(this->Data + this->Size - 1, val);
- }
-
- template<class S>
- void PushBackAlt(const S& val)
- {
- BaseType::ResizeNoConstruct(this->Size + 1);
- Allocator::ConstructAlt(this->Data + this->Size - 1, val);
- }
-
- // Append the given data to the array.
- void Append(const ValueType other[], UPInt count)
- {
- if (count)
- {
- UPInt oldSize = this->Size;
- BaseType::ResizeNoConstruct(this->Size + count);
- Allocator::ConstructArray(this->Data + oldSize, count, other);
- }
- }
-
- ValueType DefaultValue;
-};
-
-
-
-
-
-//-----------------------------------------------------------------------------------
-// ***** ArrayBase
-//
-// Resizable array. The behavior can be POD (suffix _POD) and
-// Movable (no suffix) depending on the allocator policy.
-// In case of _POD the constructors and destructors are not called.
-//
-// Arrays can't handle non-movable objects! Don't put anything in here
-// that can't be moved around by bitwise copy.
-//
-// The addresses of elements are not persistent! Don't keep the address
-// of an element; the array contents will move around as it gets resized.
-template<class ArrayData>
-class ArrayBase
-{
-public:
- typedef typename ArrayData::ValueType ValueType;
- typedef typename ArrayData::AllocatorType AllocatorType;
- typedef typename ArrayData::SizePolicyType SizePolicyType;
- typedef ArrayBase<ArrayData> SelfType;
-
-
-#undef new
- OVR_MEMORY_REDEFINE_NEW(ArrayBase)
-// Redefine operator 'new' if necessary.
-#if defined(OVR_DEFINE_NEW)
-#define new OVR_DEFINE_NEW
-#endif
-
-
- ArrayBase()
- : Data() {}
- ArrayBase(int size)
- : Data(size) {}
- ArrayBase(const SelfType& a)
- : Data(a.Data) {}
-
- ArrayBase(const ValueType& defval)
- : Data(defval) {}
- ArrayBase(const ValueType& defval, int size)
- : Data(defval, size) {}
-
- SizePolicyType* GetSizePolicy() const { return Data.Policy; }
- void SetSizePolicy(const SizePolicyType& p) { Data.Policy = p; }
-
- bool NeverShrinking()const { return Data.Policy.NeverShrinking(); }
- UPInt GetSize() const { return Data.Size; }
- bool IsEmpty() const { return Data.Size == 0; }
- UPInt GetCapacity() const { return Data.GetCapacity(); }
- UPInt GetNumBytes() const { return Data.GetCapacity() * sizeof(ValueType); }
-
- void ClearAndRelease() { Data.ClearAndRelease(); }
- void Clear() { Data.Resize(0); }
- void Resize(UPInt newSize) { Data.Resize(newSize); }
-
- // Reserve can only increase the capacity
- void Reserve(UPInt newCapacity)
- {
- if (newCapacity > Data.GetCapacity())
- Data.Reserve(newCapacity);
- }
-
- // Basic access.
- ValueType& At(UPInt index)
- {
- OVR_ASSERT(index < Data.Size);
- return Data.Data[index];
- }
- const ValueType& At(UPInt index) const
- {
- OVR_ASSERT(index < Data.Size);
- return Data.Data[index];
- }
-
- ValueType ValueAt(UPInt index) const
- {
- OVR_ASSERT(index < Data.Size);
- return Data.Data[index];
- }
-
- // Basic access.
- ValueType& operator [] (UPInt index)
- {
- OVR_ASSERT(index < Data.Size);
- return Data.Data[index];
- }
- const ValueType& operator [] (UPInt index) const
- {
- OVR_ASSERT(index < Data.Size);
- return Data.Data[index];
- }
-
- // Raw pointer to the data. Use with caution!
- const ValueType* GetDataPtr() const { return Data.Data; }
- ValueType* GetDataPtr() { return Data.Data; }
-
- // Insert the given element at the end of the array.
- void PushBack(const ValueType& val)
- {
- // DO NOT pass elements of your own vector into
- // push_back()! Since we're using references,
- // resize() may munge the element storage!
- // OVR_ASSERT(&val < &Buffer[0] || &val > &Buffer[BufferSize]);
- Data.PushBack(val);
- }
-
- template<class S>
- void PushBackAlt(const S& val)
- {
- Data.PushBackAlt(val);
- }
-
- // Remove the last element.
- void PopBack(UPInt count = 1)
- {
- OVR_ASSERT(Data.Size >= count);
- Data.Resize(Data.Size - count);
- }
-
- ValueType& PushDefault()
- {
- Data.PushBack(ValueType());
- return Back();
- }
-
- ValueType Pop()
- {
- ValueType t = Back();
- PopBack();
- return t;
- }
-
-
- // Access the first element.
- ValueType& Front() { return At(0); }
- const ValueType& Front() const { return At(0); }
-
- // Access the last element.
- ValueType& Back() { return At(Data.Size - 1); }
- const ValueType& Back() const { return At(Data.Size - 1); }
-
- // Array copy. Copies the contents of a into this array.
- const SelfType& operator = (const SelfType& a)
- {
- Resize(a.GetSize());
- for (UPInt i = 0; i < Data.Size; i++) {
- *(Data.Data + i) = a[i];
- }
- return *this;
- }
-
- // Removing multiple elements from the array.
- void RemoveMultipleAt(UPInt index, UPInt num)
- {
- OVR_ASSERT(index + num <= Data.Size);
- if (Data.Size == num)
- {
- Clear();
- }
- else
- {
- AllocatorType::DestructArray(Data.Data + index, num);
- AllocatorType::CopyArrayForward(
- Data.Data + index,
- Data.Data + index + num,
- Data.Size - num - index);
- Data.Size -= num;
- }
- }
-
- // Removing an element from the array is an expensive operation!
- // It compacts only after removing the last element.
- void RemoveAt(UPInt index)
- {
- OVR_ASSERT(index < Data.Size);
- if (Data.Size == 1)
- {
- Clear();
- }
- else
- {
- AllocatorType::Destruct(Data.Data + index);
- AllocatorType::CopyArrayForward(
- Data.Data + index,
- Data.Data + index + 1,
- Data.Size - 1 - index);
- --Data.Size;
- }
- }
-
- // Insert the given object at the given index shifting all the elements up.
- void InsertAt(UPInt index, const ValueType& val = ValueType())
- {
- OVR_ASSERT(index <= Data.Size);
-
- Data.Resize(Data.Size + 1);
- if (index < Data.Size - 1)
- {
- AllocatorType::CopyArrayBackward(
- Data.Data + index + 1,
- Data.Data + index,
- Data.Size - 1 - index);
- }
- AllocatorType::Construct(Data.Data + index, val);
- }
-
- // Insert the given object at the given index shifting all the elements up.
- void InsertMultipleAt(UPInt index, UPInt num, const ValueType& val = ValueType())
- {
- OVR_ASSERT(index <= Data.Size);
-
- Data.Resize(Data.Size + num);
- if (index < Data.Size - num)
- {
- AllocatorType::CopyArrayBackward(
- Data.Data + index + num,
- Data.Data + index,
- Data.Size - num - index);
- }
- for (UPInt i = 0; i < num; ++i)
- AllocatorType::Construct(Data.Data + index + i, val);
- }
-
- // Append the given data to the array.
- void Append(const SelfType& other)
- {
- Append(other.Data.Data, other.GetSize());
- }
-
- // Append the given data to the array.
- void Append(const ValueType other[], UPInt count)
- {
- Data.Append(other, count);
- }
-
- class Iterator
- {
- SelfType* pArray;
- SPInt CurIndex;
-
- public:
- Iterator() : pArray(0), CurIndex(-1) {}
- Iterator(SelfType* parr, SPInt idx = 0) : pArray(parr), CurIndex(idx) {}
-
- bool operator==(const Iterator& it) const { return pArray == it.pArray && CurIndex == it.CurIndex; }
- bool operator!=(const Iterator& it) const { return pArray != it.pArray || CurIndex != it.CurIndex; }
-
- Iterator& operator++()
- {
- if (pArray)
- {
- if (CurIndex < (SPInt)pArray->GetSize())
- ++CurIndex;
- }
- return *this;
- }
- Iterator operator++(int)
- {
- Iterator it(*this);
- operator++();
- return it;
- }
- Iterator& operator--()
- {
- if (pArray)
- {
- if (CurIndex >= 0)
- --CurIndex;
- }
- return *this;
- }
- Iterator operator--(int)
- {
- Iterator it(*this);
- operator--();
- return it;
- }
- Iterator operator+(int delta) const
- {
- return Iterator(pArray, CurIndex + delta);
- }
- Iterator operator-(int delta) const
- {
- return Iterator(pArray, CurIndex - delta);
- }
- SPInt operator-(const Iterator& right) const
- {
- OVR_ASSERT(pArray == right.pArray);
- return CurIndex - right.CurIndex;
- }
- ValueType& operator*() const { OVR_ASSERT(pArray); return (*pArray)[CurIndex]; }
- ValueType* operator->() const { OVR_ASSERT(pArray); return &(*pArray)[CurIndex]; }
- ValueType* GetPtr() const { OVR_ASSERT(pArray); return &(*pArray)[CurIndex]; }
-
- bool IsFinished() const { return !pArray || CurIndex < 0 || CurIndex >= (int)pArray->GetSize(); }
-
- void Remove()
- {
- if (!IsFinished())
- pArray->RemoveAt(CurIndex);
- }
-
- SPInt GetIndex() const { return CurIndex; }
- };
-
- Iterator Begin() { return Iterator(this); }
- Iterator End() { return Iterator(this, (SPInt)GetSize()); }
- Iterator Last() { return Iterator(this, (SPInt)GetSize() - 1); }
-
- class ConstIterator
- {
- const SelfType* pArray;
- SPInt CurIndex;
-
- public:
- ConstIterator() : pArray(0), CurIndex(-1) {}
- ConstIterator(const SelfType* parr, SPInt idx = 0) : pArray(parr), CurIndex(idx) {}
-
- bool operator==(const ConstIterator& it) const { return pArray == it.pArray && CurIndex == it.CurIndex; }
- bool operator!=(const ConstIterator& it) const { return pArray != it.pArray || CurIndex != it.CurIndex; }
-
- ConstIterator& operator++()
- {
- if (pArray)
- {
- if (CurIndex < (int)pArray->GetSize())
- ++CurIndex;
- }
- return *this;
- }
- ConstIterator operator++(int)
- {
- ConstIterator it(*this);
- operator++();
- return it;
- }
- ConstIterator& operator--()
- {
- if (pArray)
- {
- if (CurIndex >= 0)
- --CurIndex;
- }
- return *this;
- }
- ConstIterator operator--(int)
- {
- ConstIterator it(*this);
- operator--();
- return it;
- }
- ConstIterator operator+(int delta) const
- {
- return ConstIterator(pArray, CurIndex + delta);
- }
- ConstIterator operator-(int delta) const
- {
- return ConstIterator(pArray, CurIndex - delta);
- }
- SPInt operator-(const ConstIterator& right) const
- {
- OVR_ASSERT(pArray == right.pArray);
- return CurIndex - right.CurIndex;
- }
- const ValueType& operator*() const { OVR_ASSERT(pArray); return (*pArray)[CurIndex]; }
- const ValueType* operator->() const { OVR_ASSERT(pArray); return &(*pArray)[CurIndex]; }
- const ValueType* GetPtr() const { OVR_ASSERT(pArray); return &(*pArray)[CurIndex]; }
-
- bool IsFinished() const { return !pArray || CurIndex < 0 || CurIndex >= (int)pArray->GetSize(); }
-
- SPInt GetIndex() const { return CurIndex; }
- };
- ConstIterator Begin() const { return ConstIterator(this); }
- ConstIterator End() const { return ConstIterator(this, (SPInt)GetSize()); }
- ConstIterator Last() const { return ConstIterator(this, (SPInt)GetSize() - 1); }
-
-protected:
- ArrayData Data;
-};
-
-
-
-//-----------------------------------------------------------------------------------
-// ***** Array
-//
-// General purpose array for movable objects that require explicit
-// construction/destruction.
-template<class T, class SizePolicy=ArrayDefaultPolicy>
-class Array : public ArrayBase<ArrayData<T, ContainerAllocator<T>, SizePolicy> >
-{
-public:
- typedef T ValueType;
- typedef ContainerAllocator<T> AllocatorType;
- typedef SizePolicy SizePolicyType;
- typedef Array<T, SizePolicy> SelfType;
- typedef ArrayBase<ArrayData<T, ContainerAllocator<T>, SizePolicy> > BaseType;
-
- Array() : BaseType() {}
- Array(int size) : BaseType(size) {}
- Array(const SizePolicyType& p) : BaseType() { SetSizePolicy(p); }
- Array(const SelfType& a) : BaseType(a) {}
- const SelfType& operator=(const SelfType& a) { BaseType::operator=(a); return *this; }
-};
-
-// ***** ArrayPOD
-//
-// General purpose array for movable objects that DOES NOT require
-// construction/destruction. Constructors and destructors are not called!
-// Global heap is in use.
-template<class T, class SizePolicy=ArrayDefaultPolicy>
-class ArrayPOD : public ArrayBase<ArrayData<T, ContainerAllocator_POD<T>, SizePolicy> >
-{
-public:
- typedef T ValueType;
- typedef ContainerAllocator_POD<T> AllocatorType;
- typedef SizePolicy SizePolicyType;
- typedef ArrayPOD<T, SizePolicy> SelfType;
- typedef ArrayBase<ArrayData<T, ContainerAllocator_POD<T>, SizePolicy> > BaseType;
-
- ArrayPOD() : BaseType() {}
- ArrayPOD(int size) : BaseType(size) {}
- ArrayPOD(const SizePolicyType& p) : BaseType() { SetSizePolicy(p); }
- ArrayPOD(const SelfType& a) : BaseType(a) {}
- const SelfType& operator=(const SelfType& a) { BaseType::operator=(a); return *this; }
-};
-
-
-// ***** ArrayCPP
-//
-// General purpose, fully C++ compliant array. Can be used with non-movable data.
-// Global heap is in use.
-template<class T, class SizePolicy=ArrayDefaultPolicy>
-class ArrayCPP : public ArrayBase<ArrayData<T, ContainerAllocator_CPP<T>, SizePolicy> >
-{
-public:
- typedef T ValueType;
- typedef ContainerAllocator_CPP<T> AllocatorType;
- typedef SizePolicy SizePolicyType;
- typedef ArrayCPP<T, SizePolicy> SelfType;
- typedef ArrayBase<ArrayData<T, ContainerAllocator_CPP<T>, SizePolicy> > BaseType;
-
- ArrayCPP() : BaseType() {}
- ArrayCPP(int size) : BaseType(size) {}
- ArrayCPP(const SizePolicyType& p) : BaseType() { SetSizePolicy(p); }
- ArrayCPP(const SelfType& a) : BaseType(a) {}
- const SelfType& operator=(const SelfType& a) { BaseType::operator=(a); return *this; }
-};
-
-
-// ***** ArrayCC
-//
-// A modification of the array that uses the given default value to
-// construct the elements. The constructors and destructors are
-// properly called, the objects must be movable.
-
-template<class T, class SizePolicy=ArrayDefaultPolicy>
-class ArrayCC : public ArrayBase<ArrayDataCC<T, ContainerAllocator<T>, SizePolicy> >
-{
-public:
- typedef T ValueType;
- typedef ContainerAllocator<T> AllocatorType;
- typedef SizePolicy SizePolicyType;
- typedef ArrayCC<T, SizePolicy> SelfType;
- typedef ArrayBase<ArrayDataCC<T, ContainerAllocator<T>, SizePolicy> > BaseType;
-
- ArrayCC(const ValueType& defval) : BaseType(defval) {}
- ArrayCC(const ValueType& defval, int size) : BaseType(defval, size) {}
- ArrayCC(const ValueType& defval, const SizePolicyType& p) : BaseType(defval) { SetSizePolicy(p); }
- ArrayCC(const SelfType& a) : BaseType(a) {}
- const SelfType& operator=(const SelfType& a) { BaseType::operator=(a); return *this; }
-};
-
-} // OVR
-
-#endif
+/************************************************************************************
+
+PublicHeader: OVR.h
+Filename : OVR_Array.h
+Content : Template implementation for Array
+Created : September 19, 2012
+Notes :
+
+Copyright : Copyright 2012 Oculus VR, Inc. All Rights reserved.
+
+Use of this software is subject to the terms of the Oculus license
+agreement provided at the time of installation or download, or which
+otherwise accompanies this software in either electronic or hard copy form.
+
+************************************************************************************/
+
+#ifndef OVR_Array_h
+#define OVR_Array_h
+
+#include "OVR_ContainerAllocator.h"
+
+namespace OVR {
+
+//-----------------------------------------------------------------------------------
+// ***** ArrayDefaultPolicy
+//
+// Default resize behavior. No minimal capacity, Granularity=4,
+// Shrinking as needed. ArrayConstPolicy actually is the same as
+// ArrayDefaultPolicy, but parametrized with constants.
+// This struct is used only in order to reduce the template "matroska".
+struct ArrayDefaultPolicy
+{
+ ArrayDefaultPolicy() : Capacity(0) {}
+ ArrayDefaultPolicy(const ArrayDefaultPolicy&) : Capacity(0) {}
+
+ UPInt GetMinCapacity() const { return 0; }
+ UPInt GetGranularity() const { return 4; }
+ bool NeverShrinking() const { return 0; }
+
+ UPInt GetCapacity() const { return Capacity; }
+ void SetCapacity(UPInt capacity) { Capacity = capacity; }
+private:
+ UPInt Capacity;
+};
+
+
+//-----------------------------------------------------------------------------------
+// ***** ArrayConstPolicy
+//
+// Statically parametrized resizing behavior:
+// MinCapacity, Granularity, and Shrinking flag.
+template<int MinCapacity=0, int Granularity=4, bool NeverShrink=false>
+struct ArrayConstPolicy
+{
+ typedef ArrayConstPolicy<MinCapacity, Granularity, NeverShrink> SelfType;
+
+ ArrayConstPolicy() : Capacity(0) {}
+ ArrayConstPolicy(const SelfType&) : Capacity(0) {}
+
+ UPInt GetMinCapacity() const { return MinCapacity; }
+ UPInt GetGranularity() const { return Granularity; }
+ bool NeverShrinking() const { return NeverShrink; }
+
+ UPInt GetCapacity() const { return Capacity; }
+ void SetCapacity(UPInt capacity) { Capacity = capacity; }
+private:
+ UPInt Capacity;
+};
+
+//-----------------------------------------------------------------------------------
+// ***** ArrayDataBase
+//
+// Basic operations with array data: Reserve, Resize, Free, ArrayPolicy.
+// For internal use only: ArrayData,ArrayDataCC and others.
+template<class T, class Allocator, class SizePolicy>
+struct ArrayDataBase
+{
+ typedef T ValueType;
+ typedef Allocator AllocatorType;
+ typedef SizePolicy SizePolicyType;
+ typedef ArrayDataBase<T, Allocator, SizePolicy> SelfType;
+
+ ArrayDataBase()
+ : Data(0), Size(0), Policy() {}
+
+ ArrayDataBase(const SizePolicy& p)
+ : Data(0), Size(0), Policy(p) {}
+
+ ~ArrayDataBase()
+ {
+ Allocator::DestructArray(Data, Size);
+ Allocator::Free(Data);
+ }
+
+ UPInt GetCapacity() const
+ {
+ return Policy.GetCapacity();
+ }
+
+ void ClearAndRelease()
+ {
+ Allocator::DestructArray(Data, Size);
+ Allocator::Free(Data);
+ Data = 0;
+ Size = 0;
+ Policy.SetCapacity(0);
+ }
+
+ void Reserve(UPInt newCapacity)
+ {
+ if (Policy.NeverShrinking() && newCapacity < GetCapacity())
+ return;
+
+ if (newCapacity < Policy.GetMinCapacity())
+ newCapacity = Policy.GetMinCapacity();
+
+ // Resize the buffer.
+ if (newCapacity == 0)
+ {
+ if (Data)
+ {
+ Allocator::Free(Data);
+ Data = 0;
+ }
+ Policy.SetCapacity(0);
+ }
+ else
+ {
+ UPInt gran = Policy.GetGranularity();
+ newCapacity = (newCapacity + gran - 1) / gran * gran;
+ if (Data)
+ {
+ if (Allocator::IsMovable())
+ {
+ Data = (T*)Allocator::Realloc(Data, sizeof(T) * newCapacity);
+ }
+ else
+ {
+ T* newData = (T*)Allocator::Alloc(sizeof(T) * newCapacity);
+ UPInt i, s;
+ s = (Size < newCapacity) ? Size : newCapacity;
+ for (i = 0; i < s; ++i)
+ {
+ Allocator::Construct(&newData[i], Data[i]);
+ Allocator::Destruct(&Data[i]);
+ }
+ for (i = s; i < Size; ++i)
+ {
+ Allocator::Destruct(&Data[i]);
+ }
+ Allocator::Free(Data);
+ Data = newData;
+ }
+ }
+ else
+ {
+ Data = (T*)Allocator::Alloc(sizeof(T) * newCapacity);
+ //memset(Buffer, 0, (sizeof(ValueType) * newSize)); // Do we need this?
+ }
+ Policy.SetCapacity(newCapacity);
+ // OVR_ASSERT(Data); // need to throw (or something) on alloc failure!
+ }
+ }
+
+ // This version of Resize DOES NOT construct the elements.
+ // It's done to optimize PushBack, which uses a copy constructor
+ // instead of the default constructor and assignment
+ void ResizeNoConstruct(UPInt newSize)
+ {
+ UPInt oldSize = Size;
+
+ if (newSize < oldSize)
+ {
+ Allocator::DestructArray(Data + newSize, oldSize - newSize);
+ if (newSize < (Policy.GetCapacity() >> 1))
+ {
+ Reserve(newSize);
+ }
+ }
+ else if(newSize >= Policy.GetCapacity())
+ {
+ Reserve(newSize + (newSize >> 2));
+ }
+ //! IMPORTANT to modify Size only after Reserve completes, because garbage collectable
+ // array may use this array and may traverse it during Reserve (in the case, if
+ // collection occurs because of heap limit exceeded).
+ Size = newSize;
+ }
+
+ ValueType* Data;
+ UPInt Size;
+ SizePolicy Policy;
+};
+
+
+
+//-----------------------------------------------------------------------------------
+// ***** ArrayData
+//
+// General purpose array data.
+// For internal use only in Array, ArrayLH, ArrayPOD and so on.
+template<class T, class Allocator, class SizePolicy>
+struct ArrayData : ArrayDataBase<T, Allocator, SizePolicy>
+{
+ typedef T ValueType;
+ typedef Allocator AllocatorType;
+ typedef SizePolicy SizePolicyType;
+ typedef ArrayDataBase<T, Allocator, SizePolicy> BaseType;
+ typedef ArrayData <T, Allocator, SizePolicy> SelfType;
+
+ ArrayData()
+ : BaseType() { }
+
+ ArrayData(int size)
+ : BaseType() { Resize(size); }
+
+ ArrayData(const SelfType& a)
+ : BaseType(a.Policy) { Append(a.Data, a.Size); }
+
+
+ void Resize(UPInt newSize)
+ {
+ UPInt oldSize = this->Size;
+ BaseType::ResizeNoConstruct(newSize);
+ if(newSize > oldSize)
+ Allocator::ConstructArray(this->Data + oldSize, newSize - oldSize);
+ }
+
+ void PushBack(const ValueType& val)
+ {
+ BaseType::ResizeNoConstruct(this->Size + 1);
+ Allocator::Construct(this->Data + this->Size - 1, val);
+ }
+
+ template<class S>
+ void PushBackAlt(const S& val)
+ {
+ BaseType::ResizeNoConstruct(this->Size + 1);
+ Allocator::ConstructAlt(this->Data + this->Size - 1, val);
+ }
+
+ // Append the given data to the array.
+ void Append(const ValueType other[], UPInt count)
+ {
+ if (count)
+ {
+ UPInt oldSize = this->Size;
+ BaseType::ResizeNoConstruct(this->Size + count);
+ Allocator::ConstructArray(this->Data + oldSize, count, other);
+ }
+ }
+};
+
+
+
+//-----------------------------------------------------------------------------------
+// ***** ArrayDataCC
+//
+// A modification of ArrayData that always copy-constructs new elements
+// using a specified DefaultValue. For internal use only in ArrayCC.
+template<class T, class Allocator, class SizePolicy>
+struct ArrayDataCC : ArrayDataBase<T, Allocator, SizePolicy>
+{
+ typedef T ValueType;
+ typedef Allocator AllocatorType;
+ typedef SizePolicy SizePolicyType;
+ typedef ArrayDataBase<T, Allocator, SizePolicy> BaseType;
+ typedef ArrayDataCC <T, Allocator, SizePolicy> SelfType;
+
+ ArrayDataCC(const ValueType& defval)
+ : BaseType(), DefaultValue(defval) { }
+
+ ArrayDataCC(const ValueType& defval, int size)
+ : BaseType(), DefaultValue(defval) { Resize(size); }
+
+ ArrayDataCC(const SelfType& a)
+ : BaseType(a.Policy), DefaultValue(a.DefaultValue) { Append(a.Data, a.Size); }
+
+
+ void Resize(UPInt newSize)
+ {
+ UPInt oldSize = this->Size;
+ BaseType::ResizeNoConstruct(newSize);
+ if(newSize > oldSize)
+ Allocator::ConstructArray(this->Data + oldSize, newSize - oldSize, DefaultValue);
+ }
+
+ void PushBack(const ValueType& val)
+ {
+ BaseType::ResizeNoConstruct(this->Size + 1);
+ Allocator::Construct(this->Data + this->Size - 1, val);
+ }
+
+ template<class S>
+ void PushBackAlt(const S& val)
+ {
+ BaseType::ResizeNoConstruct(this->Size + 1);
+ Allocator::ConstructAlt(this->Data + this->Size - 1, val);
+ }
+
+ // Append the given data to the array.
+ void Append(const ValueType other[], UPInt count)
+ {
+ if (count)
+ {
+ UPInt oldSize = this->Size;
+ BaseType::ResizeNoConstruct(this->Size + count);
+ Allocator::ConstructArray(this->Data + oldSize, count, other);
+ }
+ }
+
+ ValueType DefaultValue;
+};
+
+
+
+
+
+//-----------------------------------------------------------------------------------
+// ***** ArrayBase
+//
+// Resizable array. The behavior can be POD (suffix _POD) and
+// Movable (no suffix) depending on the allocator policy.
+// In case of _POD the constructors and destructors are not called.
+//
+// Arrays can't handle non-movable objects! Don't put anything in here
+// that can't be moved around by bitwise copy.
+//
+// The addresses of elements are not persistent! Don't keep the address
+// of an element; the array contents will move around as it gets resized.
+template<class ArrayData>
+class ArrayBase
+{
+public:
+ typedef typename ArrayData::ValueType ValueType;
+ typedef typename ArrayData::AllocatorType AllocatorType;
+ typedef typename ArrayData::SizePolicyType SizePolicyType;
+ typedef ArrayBase<ArrayData> SelfType;
+
+
+#undef new
+ OVR_MEMORY_REDEFINE_NEW(ArrayBase)
+// Redefine operator 'new' if necessary.
+#if defined(OVR_DEFINE_NEW)
+#define new OVR_DEFINE_NEW
+#endif
+
+
+ ArrayBase()
+ : Data() {}
+ ArrayBase(int size)
+ : Data(size) {}
+ ArrayBase(const SelfType& a)
+ : Data(a.Data) {}
+
+ ArrayBase(const ValueType& defval)
+ : Data(defval) {}
+ ArrayBase(const ValueType& defval, int size)
+ : Data(defval, size) {}
+
+ SizePolicyType* GetSizePolicy() const { return Data.Policy; }
+ void SetSizePolicy(const SizePolicyType& p) { Data.Policy = p; }
+
+ bool NeverShrinking()const { return Data.Policy.NeverShrinking(); }
+ UPInt GetSize() const { return Data.Size; }
+ bool IsEmpty() const { return Data.Size == 0; }
+ UPInt GetCapacity() const { return Data.GetCapacity(); }
+ UPInt GetNumBytes() const { return Data.GetCapacity() * sizeof(ValueType); }
+
+ void ClearAndRelease() { Data.ClearAndRelease(); }
+ void Clear() { Data.Resize(0); }
+ void Resize(UPInt newSize) { Data.Resize(newSize); }
+
+ // Reserve can only increase the capacity
+ void Reserve(UPInt newCapacity)
+ {
+ if (newCapacity > Data.GetCapacity())
+ Data.Reserve(newCapacity);
+ }
+
+ // Basic access.
+ ValueType& At(UPInt index)
+ {
+ OVR_ASSERT(index < Data.Size);
+ return Data.Data[index];
+ }
+ const ValueType& At(UPInt index) const
+ {
+ OVR_ASSERT(index < Data.Size);
+ return Data.Data[index];
+ }
+
+ ValueType ValueAt(UPInt index) const
+ {
+ OVR_ASSERT(index < Data.Size);
+ return Data.Data[index];
+ }
+
+ // Basic access.
+ ValueType& operator [] (UPInt index)
+ {
+ OVR_ASSERT(index < Data.Size);
+ return Data.Data[index];
+ }
+ const ValueType& operator [] (UPInt index) const
+ {
+ OVR_ASSERT(index < Data.Size);
+ return Data.Data[index];
+ }
+
+ // Raw pointer to the data. Use with caution!
+ const ValueType* GetDataPtr() const { return Data.Data; }
+ ValueType* GetDataPtr() { return Data.Data; }
+
+ // Insert the given element at the end of the array.
+ void PushBack(const ValueType& val)
+ {
+ // DO NOT pass elements of your own vector into
+ // push_back()! Since we're using references,
+ // resize() may munge the element storage!
+ // OVR_ASSERT(&val < &Buffer[0] || &val > &Buffer[BufferSize]);
+ Data.PushBack(val);
+ }
+
+ template<class S>
+ void PushBackAlt(const S& val)
+ {
+ Data.PushBackAlt(val);
+ }
+
+ // Remove the last element.
+ void PopBack(UPInt count = 1)
+ {
+ OVR_ASSERT(Data.Size >= count);
+ Data.Resize(Data.Size - count);
+ }
+
+ ValueType& PushDefault()
+ {
+ Data.PushBack(ValueType());
+ return Back();
+ }
+
+ ValueType Pop()
+ {
+ ValueType t = Back();
+ PopBack();
+ return t;
+ }
+
+
+ // Access the first element.
+ ValueType& Front() { return At(0); }
+ const ValueType& Front() const { return At(0); }
+
+ // Access the last element.
+ ValueType& Back() { return At(Data.Size - 1); }
+ const ValueType& Back() const { return At(Data.Size - 1); }
+
+ // Array copy. Copies the contents of a into this array.
+ const SelfType& operator = (const SelfType& a)
+ {
+ Resize(a.GetSize());
+ for (UPInt i = 0; i < Data.Size; i++) {
+ *(Data.Data + i) = a[i];
+ }
+ return *this;
+ }
+
+ // Removing multiple elements from the array.
+ void RemoveMultipleAt(UPInt index, UPInt num)
+ {
+ OVR_ASSERT(index + num <= Data.Size);
+ if (Data.Size == num)
+ {
+ Clear();
+ }
+ else
+ {
+ AllocatorType::DestructArray(Data.Data + index, num);
+ AllocatorType::CopyArrayForward(
+ Data.Data + index,
+ Data.Data + index + num,
+ Data.Size - num - index);
+ Data.Size -= num;
+ }
+ }
+
+ // Removing an element from the array is an expensive operation!
+ // It compacts only after removing the last element.
+ void RemoveAt(UPInt index)
+ {
+ OVR_ASSERT(index < Data.Size);
+ if (Data.Size == 1)
+ {
+ Clear();
+ }
+ else
+ {
+ AllocatorType::Destruct(Data.Data + index);
+ AllocatorType::CopyArrayForward(
+ Data.Data + index,
+ Data.Data + index + 1,
+ Data.Size - 1 - index);
+ --Data.Size;
+ }
+ }
+
+ // Insert the given object at the given index shifting all the elements up.
+ void InsertAt(UPInt index, const ValueType& val = ValueType())
+ {
+ OVR_ASSERT(index <= Data.Size);
+
+ Data.Resize(Data.Size + 1);
+ if (index < Data.Size - 1)
+ {
+ AllocatorType::CopyArrayBackward(
+ Data.Data + index + 1,
+ Data.Data + index,
+ Data.Size - 1 - index);
+ }
+ AllocatorType::Construct(Data.Data + index, val);
+ }
+
+ // Insert the given object at the given index shifting all the elements up.
+ void InsertMultipleAt(UPInt index, UPInt num, const ValueType& val = ValueType())
+ {
+ OVR_ASSERT(index <= Data.Size);
+
+ Data.Resize(Data.Size + num);
+ if (index < Data.Size - num)
+ {
+ AllocatorType::CopyArrayBackward(
+ Data.Data + index + num,
+ Data.Data + index,
+ Data.Size - num - index);
+ }
+ for (UPInt i = 0; i < num; ++i)
+ AllocatorType::Construct(Data.Data + index + i, val);
+ }
+
+ // Append the given data to the array.
+ void Append(const SelfType& other)
+ {
+ Append(other.Data.Data, other.GetSize());
+ }
+
+ // Append the given data to the array.
+ void Append(const ValueType other[], UPInt count)
+ {
+ Data.Append(other, count);
+ }
+
+ class Iterator
+ {
+ SelfType* pArray;
+ SPInt CurIndex;
+
+ public:
+ Iterator() : pArray(0), CurIndex(-1) {}
+ Iterator(SelfType* parr, SPInt idx = 0) : pArray(parr), CurIndex(idx) {}
+
+ bool operator==(const Iterator& it) const { return pArray == it.pArray && CurIndex == it.CurIndex; }
+ bool operator!=(const Iterator& it) const { return pArray != it.pArray || CurIndex != it.CurIndex; }
+
+ Iterator& operator++()
+ {
+ if (pArray)
+ {
+ if (CurIndex < (SPInt)pArray->GetSize())
+ ++CurIndex;
+ }
+ return *this;
+ }
+ Iterator operator++(int)
+ {
+ Iterator it(*this);
+ operator++();
+ return it;
+ }
+ Iterator& operator--()
+ {
+ if (pArray)
+ {
+ if (CurIndex >= 0)
+ --CurIndex;
+ }
+ return *this;
+ }
+ Iterator operator--(int)
+ {
+ Iterator it(*this);
+ operator--();
+ return it;
+ }
+ Iterator operator+(int delta) const
+ {
+ return Iterator(pArray, CurIndex + delta);
+ }
+ Iterator operator-(int delta) const
+ {
+ return Iterator(pArray, CurIndex - delta);
+ }
+ SPInt operator-(const Iterator& right) const
+ {
+ OVR_ASSERT(pArray == right.pArray);
+ return CurIndex - right.CurIndex;
+ }
+ ValueType& operator*() const { OVR_ASSERT(pArray); return (*pArray)[CurIndex]; }
+ ValueType* operator->() const { OVR_ASSERT(pArray); return &(*pArray)[CurIndex]; }
+ ValueType* GetPtr() const { OVR_ASSERT(pArray); return &(*pArray)[CurIndex]; }
+
+ bool IsFinished() const { return !pArray || CurIndex < 0 || CurIndex >= (int)pArray->GetSize(); }
+
+ void Remove()
+ {
+ if (!IsFinished())
+ pArray->RemoveAt(CurIndex);
+ }
+
+ SPInt GetIndex() const { return CurIndex; }
+ };
+
+ Iterator Begin() { return Iterator(this); }
+ Iterator End() { return Iterator(this, (SPInt)GetSize()); }
+ Iterator Last() { return Iterator(this, (SPInt)GetSize() - 1); }
+
+ class ConstIterator
+ {
+ const SelfType* pArray;
+ SPInt CurIndex;
+
+ public:
+ ConstIterator() : pArray(0), CurIndex(-1) {}
+ ConstIterator(const SelfType* parr, SPInt idx = 0) : pArray(parr), CurIndex(idx) {}
+
+ bool operator==(const ConstIterator& it) const { return pArray == it.pArray && CurIndex == it.CurIndex; }
+ bool operator!=(const ConstIterator& it) const { return pArray != it.pArray || CurIndex != it.CurIndex; }
+
+ ConstIterator& operator++()
+ {
+ if (pArray)
+ {
+ if (CurIndex < (int)pArray->GetSize())
+ ++CurIndex;
+ }
+ return *this;
+ }
+ ConstIterator operator++(int)
+ {
+ ConstIterator it(*this);
+ operator++();
+ return it;
+ }
+ ConstIterator& operator--()
+ {
+ if (pArray)
+ {
+ if (CurIndex >= 0)
+ --CurIndex;
+ }
+ return *this;
+ }
+ ConstIterator operator--(int)
+ {
+ ConstIterator it(*this);
+ operator--();
+ return it;
+ }
+ ConstIterator operator+(int delta) const
+ {
+ return ConstIterator(pArray, CurIndex + delta);
+ }
+ ConstIterator operator-(int delta) const
+ {
+ return ConstIterator(pArray, CurIndex - delta);
+ }
+ SPInt operator-(const ConstIterator& right) const
+ {
+ OVR_ASSERT(pArray == right.pArray);
+ return CurIndex - right.CurIndex;
+ }
+ const ValueType& operator*() const { OVR_ASSERT(pArray); return (*pArray)[CurIndex]; }
+ const ValueType* operator->() const { OVR_ASSERT(pArray); return &(*pArray)[CurIndex]; }
+ const ValueType* GetPtr() const { OVR_ASSERT(pArray); return &(*pArray)[CurIndex]; }
+
+ bool IsFinished() const { return !pArray || CurIndex < 0 || CurIndex >= (int)pArray->GetSize(); }
+
+ SPInt GetIndex() const { return CurIndex; }
+ };
+ ConstIterator Begin() const { return ConstIterator(this); }
+ ConstIterator End() const { return ConstIterator(this, (SPInt)GetSize()); }
+ ConstIterator Last() const { return ConstIterator(this, (SPInt)GetSize() - 1); }
+
+protected:
+ ArrayData Data;
+};
+
+
+
+//-----------------------------------------------------------------------------------
+// ***** Array
+//
+// General purpose array for movable objects that require explicit
+// construction/destruction.
+template<class T, class SizePolicy=ArrayDefaultPolicy>
+class Array : public ArrayBase<ArrayData<T, ContainerAllocator<T>, SizePolicy> >
+{
+public:
+ typedef T ValueType;
+ typedef ContainerAllocator<T> AllocatorType;
+ typedef SizePolicy SizePolicyType;
+ typedef Array<T, SizePolicy> SelfType;
+ typedef ArrayBase<ArrayData<T, ContainerAllocator<T>, SizePolicy> > BaseType;
+
+ Array() : BaseType() {}
+ Array(int size) : BaseType(size) {}
+ Array(const SizePolicyType& p) : BaseType() { SetSizePolicy(p); }
+ Array(const SelfType& a) : BaseType(a) {}
+ const SelfType& operator=(const SelfType& a) { BaseType::operator=(a); return *this; }
+};
+
+// ***** ArrayPOD
+//
+// General purpose array for movable objects that DOES NOT require
+// construction/destruction. Constructors and destructors are not called!
+// Global heap is in use.
+template<class T, class SizePolicy=ArrayDefaultPolicy>
+class ArrayPOD : public ArrayBase<ArrayData<T, ContainerAllocator_POD<T>, SizePolicy> >
+{
+public:
+ typedef T ValueType;
+ typedef ContainerAllocator_POD<T> AllocatorType;
+ typedef SizePolicy SizePolicyType;
+ typedef ArrayPOD<T, SizePolicy> SelfType;
+ typedef ArrayBase<ArrayData<T, ContainerAllocator_POD<T>, SizePolicy> > BaseType;
+
+ ArrayPOD() : BaseType() {}
+ ArrayPOD(int size) : BaseType(size) {}
+ ArrayPOD(const SizePolicyType& p) : BaseType() { SetSizePolicy(p); }
+ ArrayPOD(const SelfType& a) : BaseType(a) {}
+ const SelfType& operator=(const SelfType& a) { BaseType::operator=(a); return *this; }
+};
+
+
+// ***** ArrayCPP
+//
+// General purpose, fully C++ compliant array. Can be used with non-movable data.
+// Global heap is in use.
+template<class T, class SizePolicy=ArrayDefaultPolicy>
+class ArrayCPP : public ArrayBase<ArrayData<T, ContainerAllocator_CPP<T>, SizePolicy> >
+{
+public:
+ typedef T ValueType;
+ typedef ContainerAllocator_CPP<T> AllocatorType;
+ typedef SizePolicy SizePolicyType;
+ typedef ArrayCPP<T, SizePolicy> SelfType;
+ typedef ArrayBase<ArrayData<T, ContainerAllocator_CPP<T>, SizePolicy> > BaseType;
+
+ ArrayCPP() : BaseType() {}
+ ArrayCPP(int size) : BaseType(size) {}
+ ArrayCPP(const SizePolicyType& p) : BaseType() { SetSizePolicy(p); }
+ ArrayCPP(const SelfType& a) : BaseType(a) {}
+ const SelfType& operator=(const SelfType& a) { BaseType::operator=(a); return *this; }
+};
+
+
+// ***** ArrayCC
+//
+// A modification of the array that uses the given default value to
+// construct the elements. The constructors and destructors are
+// properly called, the objects must be movable.
+
+template<class T, class SizePolicy=ArrayDefaultPolicy>
+class ArrayCC : public ArrayBase<ArrayDataCC<T, ContainerAllocator<T>, SizePolicy> >
+{
+public:
+ typedef T ValueType;
+ typedef ContainerAllocator<T> AllocatorType;
+ typedef SizePolicy SizePolicyType;
+ typedef ArrayCC<T, SizePolicy> SelfType;
+ typedef ArrayBase<ArrayDataCC<T, ContainerAllocator<T>, SizePolicy> > BaseType;
+
+ ArrayCC(const ValueType& defval) : BaseType(defval) {}
+ ArrayCC(const ValueType& defval, int size) : BaseType(defval, size) {}
+ ArrayCC(const ValueType& defval, const SizePolicyType& p) : BaseType(defval) { SetSizePolicy(p); }
+ ArrayCC(const SelfType& a) : BaseType(a) {}
+ const SelfType& operator=(const SelfType& a) { BaseType::operator=(a); return *this; }
+};
+
+} // OVR
+
+#endif
diff --git a/LibOVR/Src/Kernel/OVR_Atomic.cpp b/LibOVR/Src/Kernel/OVR_Atomic.cpp
index a2f9230..d882758 100644
--- a/LibOVR/Src/Kernel/OVR_Atomic.cpp
+++ b/LibOVR/Src/Kernel/OVR_Atomic.cpp
@@ -1,82 +1,82 @@
-/************************************************************************************
-
-Filename : OVR_Atomic.cpp
-Content : Contains atomic operations and inline fastest locking
- functionality. Will contain #ifdefs for OS efficiency.
- Have non-thread-safe implementation if not available.
-Created : September 19, 2012
-Notes :
-
-Copyright : Copyright 2012 Oculus VR, Inc. All Rights reserved.
-
-Use of this software is subject to the terms of the Oculus license
-agreement provided at the time of installation or download, or which
-otherwise accompanies this software in either electronic or hard copy form.
-
-************************************************************************************/
-
-#include "OVR_Atomic.h"
-
-#ifdef OVR_ENABLE_THREADS
-
-// Include Windows 8-Metro compatible Synchronization API
-#if defined(OVR_OS_WIN32) && defined(NTDDI_WIN8) && (NTDDI_VERSION >= NTDDI_WIN8)
-#include <synchapi.h>
-#endif
-
-
-namespace OVR {
-
-// ***** Windows Lock implementation
-
-#if defined(OVR_OS_WIN32)
-
-// ***** Standard Win32 Lock implementation
-
-// Constructors
-Lock::Lock(unsigned spinCount)
-{
-#if defined(NTDDI_WIN8) && (NTDDI_VERSION >= NTDDI_WIN8)
- // On Windows 8 we use InitializeCriticalSectionEx due to Metro-Compatibility
- InitializeCriticalSectionEx(&cs, spinCount,
- OVR_DEBUG_SELECT(NULL, CRITICAL_SECTION_NO_DEBUG_INFO));
-#else
- // Spin count init critical section function prototype for Window NT
- typedef BOOL (WINAPI *Function_InitializeCriticalSectionAndSpinCount)
- (LPCRITICAL_SECTION lpCriticalSection, DWORD dwSpinCount);
-
-
- // Try to load function dynamically so that we don't require NT
- // On Windows NT we will use InitializeCriticalSectionAndSpinCount
- static bool initTried = 0;
- static Function_InitializeCriticalSectionAndSpinCount pInitFn = 0;
-
- if (!initTried)
- {
- HMODULE hmodule = ::LoadLibrary(OVR_STR("kernel32.dll"));
- pInitFn = (Function_InitializeCriticalSectionAndSpinCount)
- ::GetProcAddress(hmodule, "InitializeCriticalSectionAndSpinCount");
- initTried = true;
- }
-
- // Initialize the critical section
- if (pInitFn)
- pInitFn(&cs, spinCount);
- else
- ::InitializeCriticalSection(&cs);
-#endif
-
-}
-
-
-Lock::~Lock()
-{
- DeleteCriticalSection(&cs);
-}
-
-
-#endif
-
-} // OVR
-
-#endif // OVR_ENABLE_THREADS
+/************************************************************************************
+
+Filename : OVR_Atomic.cpp
+Content : Contains atomic operations and inline fastest locking
+ functionality. Will contain #ifdefs for OS efficiency.
+ Have non-thread-safe implementation if not available.
+Created : September 19, 2012
+Notes :
+
+Copyright : Copyright 2012 Oculus VR, Inc. All Rights reserved.
+
+Use of this software is subject to the terms of the Oculus license
+agreement provided at the time of installation or download, or which
+otherwise accompanies this software in either electronic or hard copy form.
+
+************************************************************************************/
+
+#include "OVR_Atomic.h"
+
+#ifdef OVR_ENABLE_THREADS
+
+// Include Windows 8-Metro compatible Synchronization API
+#if defined(OVR_OS_WIN32) && defined(NTDDI_WIN8) && (NTDDI_VERSION >= NTDDI_WIN8)
+#include <synchapi.h>
+#endif
+
+
+namespace OVR {
+
+// ***** Windows Lock implementation
+
+#if defined(OVR_OS_WIN32)
+
+// ***** Standard Win32 Lock implementation
+
+// Constructors
+Lock::Lock(unsigned spinCount)
+{
+#if defined(NTDDI_WIN8) && (NTDDI_VERSION >= NTDDI_WIN8)
+ // On Windows 8 we use InitializeCriticalSectionEx due to Metro-Compatibility
+ InitializeCriticalSectionEx(&cs, spinCount,
+ OVR_DEBUG_SELECT(NULL, CRITICAL_SECTION_NO_DEBUG_INFO));
+#else
+ // Spin count init critical section function prototype for Window NT
+ typedef BOOL (WINAPI *Function_InitializeCriticalSectionAndSpinCount)
+ (LPCRITICAL_SECTION lpCriticalSection, DWORD dwSpinCount);
+
+
+ // Try to load function dynamically so that we don't require NT
+ // On Windows NT we will use InitializeCriticalSectionAndSpinCount
+ static bool initTried = 0;
+ static Function_InitializeCriticalSectionAndSpinCount pInitFn = 0;
+
+ if (!initTried)
+ {
+ HMODULE hmodule = ::LoadLibrary(OVR_STR("kernel32.dll"));
+ pInitFn = (Function_InitializeCriticalSectionAndSpinCount)
+ ::GetProcAddress(hmodule, "InitializeCriticalSectionAndSpinCount");
+ initTried = true;
+ }
+
+ // Initialize the critical section
+ if (pInitFn)
+ pInitFn(&cs, spinCount);
+ else
+ ::InitializeCriticalSection(&cs);
+#endif
+
+}
+
+
+Lock::~Lock()
+{
+ DeleteCriticalSection(&cs);
+}
+
+
+#endif
+
+} // OVR
+
+#endif // OVR_ENABLE_THREADS
diff --git a/LibOVR/Src/Kernel/OVR_Atomic.h b/LibOVR/Src/Kernel/OVR_Atomic.h
index 089125b..a8591ff 100644
--- a/LibOVR/Src/Kernel/OVR_Atomic.h
+++ b/LibOVR/Src/Kernel/OVR_Atomic.h
@@ -1,859 +1,859 @@
-/************************************************************************************
-
-PublicHeader: OVR.h
-Filename : OVR_Atomic.h
-Content : Contains atomic operations and inline fastest locking
- functionality. Will contain #ifdefs for OS efficiency.
- Have non-thread-safe implementaion if not available.
-Created : September 19, 2012
-Notes :
-
-Copyright : Copyright 2012 Oculus VR, Inc. All Rights reserved.
-
-Use of this software is subject to the terms of the Oculus license
-agreement provided at the time of installation or download, or which
-otherwise accompanies this software in either electronic or hard copy form.
-
-************************************************************************************/
-#ifndef OVR_Atomic_h
-#define OVR_Atomic_h
-
-#include "OVR_Types.h"
-
-// Include System thread functionality.
-#if defined(OVR_OS_WIN32)
-#include <windows.h>
-#else
-#include <pthread.h>
-#endif
-
-
-namespace OVR {
-
-
-// ****** Declared classes
-
-// If there is NO thread support we implement AtomicOps and
-// Lock objects as no-ops. The other classes are not defined.
-template<class C> class AtomicOps;
-template<class T> class AtomicInt;
-template<class T> class AtomicPtr;
-
-class Lock;
-
-
-//-----------------------------------------------------------------------------------
-// ***** AtomicOps
-
-// Atomic operations are provided by the AtomicOps templates class,
-// implemented through system-specific AtomicOpsRaw specializations.
-// It provides several fundamental operations such as Exchange, ExchangeAdd
-// CompareAndSet, and Store_Release. Each function includes several memory
-// synchronization versions, important for multiprocessing CPUs with weak
-// memory consistency. The following memory fencing strategies are supported:
-//
-// - NoSync. No memory synchronization is done for atomic op.
-// - Release. All other memory writes are completed before atomic op
-// writes its results.
-// - Acquire. Further memory reads are forced to wait until atomic op
-// executes, guaranteeing that the right values will be seen.
-// - Sync. A combination of Release and Acquire.
-
-
-// *** AtomicOpsRaw
-
-// AtomicOpsRaw is a specialized template that provides atomic operations
-// used by AtomicOps. This class has two fundamental qualities: (1) it
-// defines a type T of correct size, and (2) provides operations that work
-// atomically, such as Exchange_Sync and CompareAndSet_Release.
-
-// AtomicOpsRawBase class contains shared constants/classes for AtomicOpsRaw.
-// The primary thing is does is define sync class objects, whose destructor and
-// constructor provide places to insert appropriate synchronization calls, on
-// systems where such calls are necessary. So far, the breakdown is as follows:
-//
-// - X86 systems don't need custom syncs, since their exchange/atomic
-// instructions are implicitly synchronized.
-// - PowerPC requires lwsync/isync instructions that can use this mechanism.
-// - If some other systems require a mechanism where syncing type is associated
-// with a particular instruction, the default implementation (which implements
-// all Sync, Acquire, and Release modes in terms of NoSync and fence) may not
-// work. Ii that case it will need to be #ifdef-ed conditionally.
-
-struct AtomicOpsRawBase
-{
-#if !defined(OVR_ENABLE_THREADS) || defined(OVR_CPU_X86) || defined(OVR_OS_WIN32) || defined(OVR_OS_IPHONE)
- // Need to have empty constructor to avoid class 'unused' variable warning.
- struct FullSync { inline FullSync() { } };
- struct AcquireSync { inline AcquireSync() { } };
- struct ReleaseSync { inline ReleaseSync() { } };
-
-#elif defined(OVR_CPU_PPC64) || defined(OVR_CPU_PPC)
- struct FullSync { inline FullSync() { asm volatile("sync\n"); } ~FullSync() { asm volatile("isync\n"); } };
- struct AcquireSync { inline AcquireSync() { } ~AcquireSync() { asm volatile("isync\n"); } };
- struct ReleaseSync { inline ReleaseSync() { asm volatile("sync\n"); } };
-
-#elif defined(OVR_CPU_MIPS)
- struct FullSync { inline FullSync() { asm volatile("sync\n"); } ~FullSync() { asm volatile("sync\n"); } };
- struct AcquireSync { inline AcquireSync() { } ~AcquireSync() { asm volatile("sync\n"); } };
- struct ReleaseSync { inline ReleaseSync() { asm volatile("sync\n"); } };
-
-#elif defined(OVR_CPU_ARM)
- struct FullSync { inline FullSync() { asm volatile("dmb\n"); } ~FullSync() { asm volatile("dmb\n"); } };
- struct AcquireSync { inline AcquireSync() { } ~AcquireSync() { asm volatile("dmb\n"); } };
- struct ReleaseSync { inline ReleaseSync() { asm volatile("dmb\n"); } };
-
-
-#elif defined(OVR_CC_GNU) && (__GNUC__ >= 4)
- // __sync functions are already full sync
- struct FullSync { inline FullSync() { } };
- struct AcquireSync { inline AcquireSync() { } };
- struct ReleaseSync { inline ReleaseSync() { } };
-#endif
-};
-
-
-// 4-Byte raw data atomic op implementation class.
-struct AtomicOpsRaw_4ByteImpl : public AtomicOpsRawBase
-{
-#if !defined(OVR_ENABLE_THREADS)
-
- // Provide a type for no-thread-support cases. Used by AtomicOpsRaw_DefImpl.
- typedef UInt32 T;
-
- // *** Thread - Safe Atomic Versions.
-
-#elif defined(OVR_OS_WIN32)
-
- // Use special defined for VC6, where volatile is not used and
- // InterlockedCompareExchange is declared incorrectly.
- typedef LONG T;
-#if defined(OVR_CC_MSVC) && (OVR_CC_MSVC < 1300)
- typedef T* InterlockTPtr;
- typedef LPVOID ET;
- typedef ET* InterlockETPtr;
-#else
- typedef volatile T* InterlockTPtr;
- typedef T ET;
- typedef InterlockTPtr InterlockETPtr;
-#endif
- inline static T Exchange_NoSync(volatile T* p, T val) { return InterlockedExchange((InterlockTPtr)p, val); }
- inline static T ExchangeAdd_NoSync(volatile T* p, T val) { return InterlockedExchangeAdd((InterlockTPtr)p, val); }
- inline static bool CompareAndSet_NoSync(volatile T* p, T c, T val) { return InterlockedCompareExchange((InterlockETPtr)p, (ET)val, (ET)c) == (ET)c; }
-
-#elif defined(OVR_CPU_PPC64) || defined(OVR_CPU_PPC)
- typedef UInt32 T;
- static inline UInt32 Exchange_NoSync(volatile UInt32 *i, UInt32 j)
- {
- UInt32 ret;
-
- asm volatile("1:\n\t"
- "lwarx %[r],0,%[i]\n\t"
- "stwcx. %[j],0,%[i]\n\t"
- "bne- 1b\n"
- : "+m" (*i), [r] "=&b" (ret) : [i] "b" (i), [j] "b" (j) : "cc", "memory");
-
- return ret;
- }
-
- static inline UInt32 ExchangeAdd_NoSync(volatile UInt32 *i, UInt32 j)
- {
- UInt32 dummy, ret;
-
- asm volatile("1:\n\t"
- "lwarx %[r],0,%[i]\n\t"
- "add %[o],%[r],%[j]\n\t"
- "stwcx. %[o],0,%[i]\n\t"
- "bne- 1b\n"
- : "+m" (*i), [r] "=&b" (ret), [o] "=&r" (dummy) : [i] "b" (i), [j] "b" (j) : "cc", "memory");
-
- return ret;
- }
-
- static inline bool CompareAndSet_NoSync(volatile UInt32 *i, UInt32 c, UInt32 value)
- {
- UInt32 ret;
-
- asm volatile("1:\n\t"
- "lwarx %[r],0,%[i]\n\t"
- "cmpw 0,%[r],%[cmp]\n\t"
- "mfcr %[r]\n\t"
- "bne- 2f\n\t"
- "stwcx. %[val],0,%[i]\n\t"
- "bne- 1b\n\t"
- "2:\n"
- : "+m" (*i), [r] "=&b" (ret) : [i] "b" (i), [cmp] "b" (c), [val] "b" (value) : "cc", "memory");
-
- return (ret & 0x20000000) ? 1 : 0;
- }
-
-#elif defined(OVR_CPU_MIPS)
- typedef UInt32 T;
-
- static inline UInt32 Exchange_NoSync(volatile UInt32 *i, UInt32 j)
- {
- UInt32 ret;
-
- asm volatile("1:\n\t"
- "ll %[r],0(%[i])\n\t"
- "sc %[j],0(%[i])\n\t"
- "beq %[j],$0,1b\n\t"
- "nop \n"
- : "+m" (*i), [r] "=&d" (ret) : [i] "d" (i), [j] "d" (j) : "cc", "memory");
-
- return ret;
- }
-
- static inline UInt32 ExchangeAdd_NoSync(volatile UInt32 *i, UInt32 j)
- {
- UInt32 ret;
-
- asm volatile("1:\n\t"
- "ll %[r],0(%[i])\n\t"
- "addu %[j],%[r],%[j]\n\t"
- "sc %[j],0(%[i])\n\t"
- "beq %[j],$0,1b\n\t"
- "nop \n"
- : "+m" (*i), [r] "=&d" (ret) : [i] "d" (i), [j] "d" (j) : "cc", "memory");
-
- return ret;
- }
-
- static inline bool CompareAndSet_NoSync(volatile UInt32 *i, UInt32 c, UInt32 value)
- {
- UInt32 ret, dummy;
-
- asm volatile("1:\n\t"
- "move %[r],$0\n\t"
- "ll %[o],0(%[i])\n\t"
- "bne %[o],%[c],2f\n\t"
- "move %[r],%[v]\n\t"
- "sc %[r],0(%[i])\n\t"
- "beq %[r],$0,1b\n\t"
- "nop \n\t"
- "2:\n"
- : "+m" (*i),[r] "=&d" (ret), [o] "=&d" (dummy) : [i] "d" (i), [c] "d" (c), [v] "d" (value)
- : "cc", "memory");
-
- return ret;
- }
-
-#elif defined(OVR_CPU_ARM) && defined(OVR_CC_ARM)
- typedef UInt32 T;
-
- static inline UInt32 Exchange_NoSync(volatile UInt32 *i, UInt32 j)
- {
- for(;;)
- {
- T r = __ldrex(i);
- if (__strex(j, i) == 0)
- return r;
- }
- }
- static inline UInt32 ExchangeAdd_NoSync(volatile UInt32 *i, UInt32 j)
- {
- for(;;)
- {
- T r = __ldrex(i);
- if (__strex(r + j, i) == 0)
- return r;
- }
- }
-
- static inline bool CompareAndSet_NoSync(volatile UInt32 *i, UInt32 c, UInt32 value)
- {
- for(;;)
- {
- T r = __ldrex(i);
- if (r != c)
- return 0;
- if (__strex(value, i) == 0)
- return 1;
- }
- }
-
-#elif defined(OVR_CPU_ARM)
- typedef UInt32 T;
-
- static inline UInt32 Exchange_NoSync(volatile UInt32 *i, UInt32 j)
- {
- UInt32 ret, dummy;
-
- asm volatile("1:\n\t"
- "ldrex %[r],[%[i]]\n\t"
- "strex %[t],%[j],[%[i]]\n\t"
- "cmp %[t],#0\n\t"
- "bne 1b\n\t"
- : "+m" (*i), [r] "=&r" (ret), [t] "=&r" (dummy) : [i] "r" (i), [j] "r" (j) : "cc", "memory");
-
- return ret;
- }
-
- static inline UInt32 ExchangeAdd_NoSync(volatile UInt32 *i, UInt32 j)
- {
- UInt32 ret, dummy, test;
-
- asm volatile("1:\n\t"
- "ldrex %[r],[%[i]]\n\t"
- "add %[o],%[r],%[j]\n\t"
- "strex %[t],%[o],[%[i]]\n\t"
- "cmp %[t],#0\n\t"
- "bne 1b\n\t"
- : "+m" (*i), [r] "=&r" (ret), [o] "=&r" (dummy), [t] "=&r" (test) : [i] "r" (i), [j] "r" (j) : "cc", "memory");
-
- return ret;
- }
-
- static inline bool CompareAndSet_NoSync(volatile UInt32 *i, UInt32 c, UInt32 value)
- {
- UInt32 ret = 1, dummy, test;
-
- asm volatile("1:\n\t"
- "ldrex %[o],[%[i]]\n\t"
- "cmp %[o],%[c]\n\t"
- "bne 2f\n\t"
- "strex %[r],%[v],[%[i]]\n\t"
- "cmp %[r],#0\n\t"
- "bne 1b\n\t"
- "2:\n"
- : "+m" (*i),[r] "=&r" (ret), [o] "=&r" (dummy), [t] "=&r" (test) : [i] "r" (i), [c] "r" (c), [v] "r" (value)
- : "cc", "memory");
-
- return !ret;
- }
-
-#elif defined(OVR_CPU_X86)
- typedef UInt32 T;
-
- static inline UInt32 Exchange_NoSync(volatile UInt32 *i, UInt32 j)
- {
- asm volatile("xchgl %1,%[i]\n"
- : "+m" (*i), "=q" (j) : [i] "m" (*i), "1" (j) : "cc", "memory");
-
- return j;
- }
-
- static inline UInt32 ExchangeAdd_NoSync(volatile UInt32 *i, UInt32 j)
- {
- asm volatile("lock; xaddl %1,%[i]\n"
- : "+m" (*i), "+q" (j) : [i] "m" (*i) : "cc", "memory");
-
- return j;
- }
-
- static inline bool CompareAndSet_NoSync(volatile UInt32 *i, UInt32 c, UInt32 value)
- {
- UInt32 ret;
-
- asm volatile("lock; cmpxchgl %[v],%[i]\n"
- : "+m" (*i), "=a" (ret) : [i] "m" (*i), "1" (c), [v] "q" (value) : "cc", "memory");
-
- return (ret == c);
- }
-
-#elif defined(OVR_CC_GNU) && (__GNUC__ >= 4 && __GNUC_MINOR__ >= 1)
-
- typedef UInt32 T;
-
- static inline T Exchange_NoSync(volatile T *i, T j)
- {
- T v;
- do {
- v = *i;
- } while (!__sync_bool_compare_and_swap(i, v, j));
- return v;
- }
-
- static inline T ExchangeAdd_NoSync(volatile T *i, T j)
- {
- return __sync_fetch_and_add(i, j);
- }
-
- static inline bool CompareAndSet_NoSync(volatile T *i, T c, T value)
- {
- return __sync_bool_compare_and_swap(i, c, value);
- }
-
-#endif // OS
-};
-
-
-// 8-Byte raw data data atomic op implementation class.
-// Currently implementation is provided only on systems with 64-bit pointers.
-struct AtomicOpsRaw_8ByteImpl : public AtomicOpsRawBase
-{
-#if !defined(OVR_64BIT_POINTERS) || !defined(OVR_ENABLE_THREADS)
-
- // Provide a type for no-thread-support cases. Used by AtomicOpsRaw_DefImpl.
- typedef UInt64 T;
-
- // *** Thread - Safe OS specific versions.
-#elif defined(OVR_OS_WIN32)
-
- // This is only for 64-bit systems.
- typedef LONG64 T;
- typedef volatile T* InterlockTPtr;
- inline static T Exchange_NoSync(volatile T* p, T val) { return InterlockedExchange64((InterlockTPtr)p, val); }
- inline static T ExchangeAdd_NoSync(volatile T* p, T val) { return InterlockedExchangeAdd64((InterlockTPtr)p, val); }
- inline static bool CompareAndSet_NoSync(volatile T* p, T c, T val) { return InterlockedCompareExchange64((InterlockTPtr)p, val, c) == c; }
-
-#elif defined(OVR_CPU_PPC64)
-
- typedef UInt64 T;
-
- static inline UInt64 Exchange_NoSync(volatile UInt64 *i, UInt64 j)
- {
- UInt64 dummy, ret;
-
- asm volatile("1:\n\t"
- "ldarx %[r],0,%[i]\n\t"
- "mr %[o],%[j]\n\t"
- "stdcx. %[o],0,%[i]\n\t"
- "bne- 1b\n"
- : "+m" (*i), [r] "=&b" (ret), [o] "=&r" (dummy) : [i] "b" (i), [j] "b" (j) : "cc");
-
- return ret;
- }
-
- static inline UInt64 ExchangeAdd_NoSync(volatile UInt64 *i, UInt64 j)
- {
- UInt64 dummy, ret;
-
- asm volatile("1:\n\t"
- "ldarx %[r],0,%[i]\n\t"
- "add %[o],%[r],%[j]\n\t"
- "stdcx. %[o],0,%[i]\n\t"
- "bne- 1b\n"
- : "+m" (*i), [r] "=&b" (ret), [o] "=&r" (dummy) : [i] "b" (i), [j] "b" (j) : "cc");
-
- return ret;
- }
-
- static inline bool CompareAndSet_NoSync(volatile UInt64 *i, UInt64 c, UInt64 value)
- {
- UInt64 ret, dummy;
-
- asm volatile("1:\n\t"
- "ldarx %[r],0,%[i]\n\t"
- "cmpw 0,%[r],%[cmp]\n\t"
- "mfcr %[r]\n\t"
- "bne- 2f\n\t"
- "stdcx. %[val],0,%[i]\n\t"
- "bne- 1b\n\t"
- "2:\n"
- : "+m" (*i), [r] "=&b" (ret), [o] "=&r" (dummy) : [i] "b" (i), [cmp] "b" (c), [val] "b" (value) : "cc");
-
- return (ret & 0x20000000) ? 1 : 0;
- }
-
-#elif defined(OVR_CC_GNU) && (__GNUC__ >= 4 && __GNUC_MINOR__ >= 1)
-
- typedef UInt64 T;
-
- static inline T Exchange_NoSync(volatile T *i, T j)
- {
- T v;
- do {
- v = *i;
- } while (!__sync_bool_compare_and_swap(i, v, j));
- return v;
- }
-
- static inline T ExchangeAdd_NoSync(volatile T *i, T j)
- {
- return __sync_fetch_and_add(i, j);
- }
-
- static inline bool CompareAndSet_NoSync(volatile T *i, T c, T value)
- {
- return __sync_bool_compare_and_swap(i, c, value);
- }
-
-#endif // OS
-};
-
-
-// Default implementation for AtomicOpsRaw; provides implementation of mem-fenced
-// atomic operations where fencing is done with a sync object wrapped around a NoSync
-// operation implemented in the base class. If such implementation is not possible
-// on a given platform, #ifdefs can be used to disable it and then op functions can be
-// implemented individually in the appropriate AtomicOpsRaw<size> class.
-
-template<class O>
-struct AtomicOpsRaw_DefImpl : public O
-{
- typedef typename O::T O_T;
- typedef typename O::FullSync O_FullSync;
- typedef typename O::AcquireSync O_AcquireSync;
- typedef typename O::ReleaseSync O_ReleaseSync;
-
- // If there is no thread support, provide the default implementation. In this case,
- // the base class (0) must still provide the T declaration.
-#ifndef OVR_ENABLE_THREADS
-
- // Atomic exchange of val with argument. Returns old val.
- inline static O_T Exchange_NoSync(volatile O_T* p, O_T val) { O_T old = *p; *p = val; return old; }
- // Adds a new val to argument; returns its old val.
- inline static O_T ExchangeAdd_NoSync(volatile O_T* p, O_T val) { O_T old = *p; *p += val; return old; }
- // Compares the argument data with 'c' val.
- // If succeeded, stores val int '*p' and returns true; otherwise returns false.
- inline static bool CompareAndSet_NoSync(volatile O_T* p, O_T c, O_T val) { if (*p==c) { *p = val; return 1; } return 0; }
-
-#endif
-
- // If NoSync wrapped implementation may not be possible, it this block should be
- // replaced with per-function implementation in O.
- // "AtomicOpsRaw_DefImpl<O>::" prefix in calls below.
- inline static O_T Exchange_Sync(volatile O_T* p, O_T val) { O_FullSync sync; OVR_UNUSED(sync); return AtomicOpsRaw_DefImpl<O>::Exchange_NoSync(p, val); }
- inline static O_T Exchange_Release(volatile O_T* p, O_T val) { O_ReleaseSync sync; OVR_UNUSED(sync); return AtomicOpsRaw_DefImpl<O>::Exchange_NoSync(p, val); }
- inline static O_T Exchange_Acquire(volatile O_T* p, O_T val) { O_AcquireSync sync; OVR_UNUSED(sync); return AtomicOpsRaw_DefImpl<O>::Exchange_NoSync(p, val); }
- inline static O_T ExchangeAdd_Sync(volatile O_T* p, O_T val) { O_FullSync sync; OVR_UNUSED(sync); return AtomicOpsRaw_DefImpl<O>::ExchangeAdd_NoSync(p, val); }
- inline static O_T ExchangeAdd_Release(volatile O_T* p, O_T val) { O_ReleaseSync sync; OVR_UNUSED(sync); return AtomicOpsRaw_DefImpl<O>::ExchangeAdd_NoSync(p, val); }
- inline static O_T ExchangeAdd_Acquire(volatile O_T* p, O_T val) { O_AcquireSync sync; OVR_UNUSED(sync); return AtomicOpsRaw_DefImpl<O>::ExchangeAdd_NoSync(p, val); }
- inline static bool CompareAndSet_Sync(volatile O_T* p, O_T c, O_T val) { O_FullSync sync; OVR_UNUSED(sync); return AtomicOpsRaw_DefImpl<O>::CompareAndSet_NoSync(p,c,val); }
- inline static bool CompareAndSet_Release(volatile O_T* p, O_T c, O_T val) { O_ReleaseSync sync; OVR_UNUSED(sync); return AtomicOpsRaw_DefImpl<O>::CompareAndSet_NoSync(p,c,val); }
- inline static bool CompareAndSet_Acquire(volatile O_T* p, O_T c, O_T val) { O_AcquireSync sync; OVR_UNUSED(sync); return AtomicOpsRaw_DefImpl<O>::CompareAndSet_NoSync(p,c,val); }
-
- // Loads and stores with memory fence. These have only the relevant versions.
-#ifdef OVR_CPU_X86
- // On X86, Store_Release is implemented as exchange. Note that we can also
- // consider 'sfence' in the future, although it is not as compatible with older CPUs.
- inline static void Store_Release(volatile O_T* p, O_T val) { Exchange_Release(p, val); }
-#else
- inline static void Store_Release(volatile O_T* p, O_T val) { O_ReleaseSync sync; OVR_UNUSED(sync); *p = val; }
-#endif
- inline static O_T Load_Acquire(const volatile O_T* p) { O_AcquireSync sync; OVR_UNUSED(sync); return *p; }
-};
-
-
-template<int size>
-struct AtomicOpsRaw : public AtomicOpsRawBase { };
-
-template<>
-struct AtomicOpsRaw<4> : public AtomicOpsRaw_DefImpl<AtomicOpsRaw_4ByteImpl>
-{
- // Ensure that assigned type size is correct.
- AtomicOpsRaw()
- { OVR_COMPILER_ASSERT(sizeof(AtomicOpsRaw_DefImpl<AtomicOpsRaw_4ByteImpl>::T) == 4); }
-};
-template<>
-struct AtomicOpsRaw<8> : public AtomicOpsRaw_DefImpl<AtomicOpsRaw_8ByteImpl>
-{
- AtomicOpsRaw()
- { OVR_COMPILER_ASSERT(sizeof(AtomicOpsRaw_DefImpl<AtomicOpsRaw_8ByteImpl>::T) == 8); }
-};
-
-
-// *** AtomicOps - implementation of atomic Ops for specified class
-
-// Implements atomic ops on a class, provided that the object is either
-// 4 or 8 bytes in size (depending on the AtomicOpsRaw specializations
-// available). Relies on AtomicOpsRaw for much of implementation.
-
-template<class C>
-class AtomicOps
-{
- typedef AtomicOpsRaw<sizeof(C)> Ops;
- typedef typename Ops::T T;
- typedef volatile typename Ops::T* PT;
- // We cast through unions to (1) avoid pointer size compiler warnings
- // and (2) ensure that there are no problems with strict pointer aliasing.
- union C2T_union { C c; T t; };
-
-public:
- // General purpose implementation for standard syncs.
- inline static C Exchange_Sync(volatile C* p, C val) { C2T_union u; u.c = val; u.t = Ops::Exchange_Sync((PT)p, u.t); return u.c; }
- inline static C Exchange_Release(volatile C* p, C val) { C2T_union u; u.c = val; u.t = Ops::Exchange_Release((PT)p, u.t); return u.c; }
- inline static C Exchange_Acquire(volatile C* p, C val) { C2T_union u; u.c = val; u.t = Ops::Exchange_Acquire((PT)p, u.t); return u.c; }
- inline static C Exchange_NoSync(volatile C* p, C val) { C2T_union u; u.c = val; u.t = Ops::Exchange_NoSync((PT)p, u.t); return u.c; }
- inline static C ExchangeAdd_Sync(volatile C* p, C val) { C2T_union u; u.c = val; u.t = Ops::ExchangeAdd_Sync((PT)p, u.t); return u.c; }
- inline static C ExchangeAdd_Release(volatile C* p, C val) { C2T_union u; u.c = val; u.t = Ops::ExchangeAdd_Release((PT)p, u.t); return u.c; }
- inline static C ExchangeAdd_Acquire(volatile C* p, C val) { C2T_union u; u.c = val; u.t = Ops::ExchangeAdd_Acquire((PT)p, u.t); return u.c; }
- inline static C ExchangeAdd_NoSync(volatile C* p, C val) { C2T_union u; u.c = val; u.t = Ops::ExchangeAdd_NoSync((PT)p, u.t); return u.c; }
- inline static bool CompareAndSet_Sync(volatile C* p, C c, C val) { C2T_union u,cu; u.c = val; cu.c = c; return Ops::CompareAndSet_Sync((PT)p, cu.t, u.t); }
- inline static bool CompareAndSet_Release(volatile C* p, C c, C val){ C2T_union u,cu; u.c = val; cu.c = c; return Ops::CompareAndSet_Release((PT)p, cu.t, u.t); }
- inline static bool CompareAndSet_Relse(volatile C* p, C c, C val){ C2T_union u,cu; u.c = val; cu.c = c; return Ops::CompareAndSet_Acquire((PT)p, cu.t, u.t); }
- inline static bool CompareAndSet_NoSync(volatile C* p, C c, C val) { C2T_union u,cu; u.c = val; cu.c = c; return Ops::CompareAndSet_NoSync((PT)p, cu.t, u.t); }
- // Loads and stores with memory fence. These have only the relevant versions.
- inline static void Store_Release(volatile C* p, C val) { C2T_union u; u.c = val; Ops::Store_Release((PT)p, u.t); }
- inline static C Load_Acquire(const volatile C* p) { C2T_union u; u.t = Ops::Load_Acquire((PT)p); return u.c; }
-};
-
-
-
-// Atomic value base class - implements operations shared for integers and pointers.
-template<class T>
-class AtomicValueBase
-{
-protected:
- typedef AtomicOps<T> Ops;
-public:
-
- volatile T Value;
-
- inline AtomicValueBase() { }
- explicit inline AtomicValueBase(T val) { Ops::Store_Release(&Value, val); }
-
- // Most libraries (TBB and Joshua Scholar's) library do not do Load_Acquire
- // here, since most algorithms do not require atomic loads. Needs some research.
- inline operator T() const { return Value; }
-
- // *** Standard Atomic inlines
- inline T Exchange_Sync(T val) { return Ops::Exchange_Sync(&Value, val); }
- inline T Exchange_Release(T val) { return Ops::Exchange_Release(&Value, val); }
- inline T Exchange_Acquire(T val) { return Ops::Exchange_Acquire(&Value, val); }
- inline T Exchange_NoSync(T val) { return Ops::Exchange_NoSync(&Value, val); }
- inline bool CompareAndSet_Sync(T c, T val) { return Ops::CompareAndSet_Sync(&Value, c, val); }
- inline bool CompareAndSet_Release(T c, T val) { return Ops::CompareAndSet_Release(&Value, c, val); }
- inline bool CompareAndSet_Acquire(T c, T val) { return Ops::CompareAndSet_Relse(&Value, c, val); }
- inline bool CompareAndSet_NoSync(T c, T val) { return Ops::CompareAndSet_NoSync(&Value, c, val); }
- // Load & Store.
- inline void Store_Release(T val) { Ops::Store_Release(&Value, val); }
- inline T Load_Acquire() const { return Ops::Load_Acquire(&Value); }
-};
-
-
-// ***** AtomicPtr - Atomic pointer template
-
-// This pointer class supports atomic assignments with release,
-// increment / decrement operations, and conditional compare + set.
-
-template<class T>
-class AtomicPtr : public AtomicValueBase<T*>
-{
- typedef typename AtomicValueBase<T*>::Ops Ops;
-
-public:
- // Initialize pointer value to 0 by default; use Store_Release only with explicit constructor.
- inline AtomicPtr() : AtomicValueBase<T*>() { this->Value = 0; }
- explicit inline AtomicPtr(T* val) : AtomicValueBase<T*>(val) { }
-
- // Pointer access.
- inline T* operator -> () const { return this->Load_Acquire(); }
-
- // It looks like it is convenient to have Load_Acquire characteristics
- // for this, since that is convenient for algorithms such as linked
- // list traversals that can be added to bu another thread.
- inline operator T* () const { return this->Load_Acquire(); }
-
-
- // *** Standard Atomic inlines (applicable to pointers)
-
- // ExhangeAdd considers pointer size for pointers.
- template<class I>
- inline T* ExchangeAdd_Sync(I incr) { return Ops::ExchangeAdd_Sync(&this->Value, ((T*)0) + incr); }
- template<class I>
- inline T* ExchangeAdd_Release(I incr) { return Ops::ExchangeAdd_Release(&this->Value, ((T*)0) + incr); }
- template<class I>
- inline T* ExchangeAdd_Acquire(I incr) { return Ops::ExchangeAdd_Acquire(&this->Value, ((T*)0) + incr); }
- template<class I>
- inline T* ExchangeAdd_NoSync(I incr) { return Ops::ExchangeAdd_NoSync(&this->Value, ((T*)0) + incr); }
-
- // *** Atomic Operators
-
- inline T* operator = (T* val) { this->Store_Release(val); return val; }
-
- template<class I>
- inline T* operator += (I val) { return ExchangeAdd_Sync(val) + val; }
- template<class I>
- inline T* operator -= (I val) { return operator += (-val); }
-
- inline T* operator ++ () { return ExchangeAdd_Sync(1) + 1; }
- inline T* operator -- () { return ExchangeAdd_Sync(-1) - 1; }
- inline T* operator ++ (int) { return ExchangeAdd_Sync(1); }
- inline T* operator -- (int) { return ExchangeAdd_Sync(-1); }
-};
-
-
-// ***** AtomicInt - Atomic integer template
-
-// Implements an atomic integer type; the exact type to use is provided
-// as an argument. Supports atomic Acquire / Release semantics, atomic
-// arithmetic operations, and atomic conditional compare + set.
-
-template<class T>
-class AtomicInt : public AtomicValueBase<T>
-{
- typedef typename AtomicValueBase<T>::Ops Ops;
-
-public:
- inline AtomicInt() : AtomicValueBase<T>() { }
- explicit inline AtomicInt(T val) : AtomicValueBase<T>(val) { }
-
-
- // *** Standard Atomic inlines (applicable to int)
- inline T ExchangeAdd_Sync(T val) { return Ops::ExchangeAdd_Sync(&this->Value, val); }
- inline T ExchangeAdd_Release(T val) { return Ops::ExchangeAdd_Release(&this->Value, val); }
- inline T ExchangeAdd_Acquire(T val) { return Ops::ExchangeAdd_Acquire(&this->Value, val); }
- inline T ExchangeAdd_NoSync(T val) { return Ops::ExchangeAdd_NoSync(&this->Value, val); }
- // These increments could be more efficient because they don't return a value.
- inline void Increment_Sync() { ExchangeAdd_Sync((T)1); }
- inline void Increment_Release() { ExchangeAdd_Release((T)1); }
- inline void Increment_Acquire() { ExchangeAdd_Acquire((T)1); }
- inline void Increment_NoSync() { ExchangeAdd_NoSync((T)1); }
-
- // *** Atomic Operators
-
- inline T operator = (T val) { this->Store_Release(val); return val; }
- inline T operator += (T val) { return ExchangeAdd_Sync(val) + val; }
- inline T operator -= (T val) { return ExchangeAdd_Sync(0 - val) - val; }
-
- inline T operator ++ () { return ExchangeAdd_Sync((T)1) + 1; }
- inline T operator -- () { return ExchangeAdd_Sync(((T)0)-1) - 1; }
- inline T operator ++ (int) { return ExchangeAdd_Sync((T)1); }
- inline T operator -- (int) { return ExchangeAdd_Sync(((T)0)-1); }
-
- // More complex atomic operations. Leave it to compiler whether to optimize them or not.
- T operator &= (T arg)
- {
- T comp, newVal;
- do {
- comp = this->Value;
- newVal = comp & arg;
- } while(!this->CompareAndSet_Sync(comp, newVal));
- return newVal;
- }
-
- T operator |= (T arg)
- {
- T comp, newVal;
- do {
- comp = this->Value;
- newVal = comp | arg;
- } while(!this->CompareAndSet_Sync(comp, newVal));
- return newVal;
- }
-
- T operator ^= (T arg)
- {
- T comp, newVal;
- do {
- comp = this->Value;
- newVal = comp ^ arg;
- } while(!this->CompareAndSet_Sync(comp, newVal));
- return newVal;
- }
-
- T operator *= (T arg)
- {
- T comp, newVal;
- do {
- comp = this->Value;
- newVal = comp * arg;
- } while(!this->CompareAndSet_Sync(comp, newVal));
- return newVal;
- }
-
- T operator /= (T arg)
- {
- T comp, newVal;
- do {
- comp = this->Value;
- newVal = comp / arg;
- } while(!CompareAndSet_Sync(comp, newVal));
- return newVal;
- }
-
- T operator >>= (unsigned bits)
- {
- T comp, newVal;
- do {
- comp = this->Value;
- newVal = comp >> bits;
- } while(!CompareAndSet_Sync(comp, newVal));
- return newVal;
- }
-
- T operator <<= (unsigned bits)
- {
- T comp, newVal;
- do {
- comp = this->Value;
- newVal = comp << bits;
- } while(!this->CompareAndSet_Sync(comp, newVal));
- return newVal;
- }
-};
-
-
-
-//-----------------------------------------------------------------------------------
-// ***** Lock
-
-// Lock is a simplest and most efficient mutual-exclusion lock class.
-// Unlike Mutex, it cannot be waited on.
-
-class Lock
-{
- // NOTE: Locks are not allocatable and they themselves should not allocate
- // memory by standard means. This is the case because StandardAllocator
- // relies on this class.
- // Make 'delete' private. Don't do this for 'new' since it can be redefined.
- void operator delete(void*) {}
-
-
- // *** Lock implementation for various platforms.
-
-#if !defined(OVR_ENABLE_THREADS)
-
-public:
- // With no thread support, lock does nothing.
- inline Lock() { }
- inline Lock(unsigned) { }
- inline ~Lock() { }
- inline void DoLock() { }
- inline void Unlock() { }
-
- // Windows.
-#elif defined(OVR_OS_WIN32)
-
- CRITICAL_SECTION cs;
-public:
- Lock(unsigned spinCount = 0);
- ~Lock();
- // Locking functions.
- inline void DoLock() { ::EnterCriticalSection(&cs); }
- inline void Unlock() { ::LeaveCriticalSection(&cs); }
-
-#else
- pthread_mutex_t mutex;
-
-public:
- static pthread_mutexattr_t RecursiveAttr;
- static bool RecursiveAttrInit;
-
- Lock (unsigned dummy = 0)
- {
- if (!RecursiveAttrInit)
- {
- pthread_mutexattr_init(&RecursiveAttr);
- pthread_mutexattr_settype(&RecursiveAttr, PTHREAD_MUTEX_RECURSIVE);
- RecursiveAttrInit = 1;
- }
- pthread_mutex_init(&mutex,&RecursiveAttr);
- }
- ~Lock () { pthread_mutex_destroy(&mutex); }
- inline void DoLock() { pthread_mutex_lock(&mutex); }
- inline void Unlock() { pthread_mutex_unlock(&mutex); }
-
-#endif // OVR_ENABLE_THREDS
-
-
-public:
- // Locker class, used for automatic locking
- class Locker
- {
- public:
- Lock *pLock;
- inline Locker(Lock *plock)
- { pLock = plock; pLock->DoLock(); }
- inline ~Locker()
- { pLock->Unlock(); }
- };
-};
-
-
-
-} // OVR
-
-#endif
+/************************************************************************************
+
+PublicHeader: OVR.h
+Filename : OVR_Atomic.h
+Content : Contains atomic operations and inline fastest locking
+ functionality. Will contain #ifdefs for OS efficiency.
+ Have non-thread-safe implementaion if not available.
+Created : September 19, 2012
+Notes :
+
+Copyright : Copyright 2012 Oculus VR, Inc. All Rights reserved.
+
+Use of this software is subject to the terms of the Oculus license
+agreement provided at the time of installation or download, or which
+otherwise accompanies this software in either electronic or hard copy form.
+
+************************************************************************************/
+#ifndef OVR_Atomic_h
+#define OVR_Atomic_h
+
+#include "OVR_Types.h"
+
+// Include System thread functionality.
+#if defined(OVR_OS_WIN32)
+#include <windows.h>
+#else
+#include <pthread.h>
+#endif
+
+
+namespace OVR {
+
+
+// ****** Declared classes
+
+// If there is NO thread support we implement AtomicOps and
+// Lock objects as no-ops. The other classes are not defined.
+template<class C> class AtomicOps;
+template<class T> class AtomicInt;
+template<class T> class AtomicPtr;
+
+class Lock;
+
+
+//-----------------------------------------------------------------------------------
+// ***** AtomicOps
+
+// Atomic operations are provided by the AtomicOps templates class,
+// implemented through system-specific AtomicOpsRaw specializations.
+// It provides several fundamental operations such as Exchange, ExchangeAdd
+// CompareAndSet, and Store_Release. Each function includes several memory
+// synchronization versions, important for multiprocessing CPUs with weak
+// memory consistency. The following memory fencing strategies are supported:
+//
+// - NoSync. No memory synchronization is done for atomic op.
+// - Release. All other memory writes are completed before atomic op
+// writes its results.
+// - Acquire. Further memory reads are forced to wait until atomic op
+// executes, guaranteeing that the right values will be seen.
+// - Sync. A combination of Release and Acquire.
+
+
+// *** AtomicOpsRaw
+
+// AtomicOpsRaw is a specialized template that provides atomic operations
+// used by AtomicOps. This class has two fundamental qualities: (1) it
+// defines a type T of correct size, and (2) provides operations that work
+// atomically, such as Exchange_Sync and CompareAndSet_Release.
+
+// AtomicOpsRawBase class contains shared constants/classes for AtomicOpsRaw.
+// The primary thing is does is define sync class objects, whose destructor and
+// constructor provide places to insert appropriate synchronization calls, on
+// systems where such calls are necessary. So far, the breakdown is as follows:
+//
+// - X86 systems don't need custom syncs, since their exchange/atomic
+// instructions are implicitly synchronized.
+// - PowerPC requires lwsync/isync instructions that can use this mechanism.
+// - If some other systems require a mechanism where syncing type is associated
+// with a particular instruction, the default implementation (which implements
+// all Sync, Acquire, and Release modes in terms of NoSync and fence) may not
+// work. Ii that case it will need to be #ifdef-ed conditionally.
+
+struct AtomicOpsRawBase
+{
+#if !defined(OVR_ENABLE_THREADS) || defined(OVR_CPU_X86) || defined(OVR_OS_WIN32) || defined(OVR_OS_IPHONE)
+ // Need to have empty constructor to avoid class 'unused' variable warning.
+ struct FullSync { inline FullSync() { } };
+ struct AcquireSync { inline AcquireSync() { } };
+ struct ReleaseSync { inline ReleaseSync() { } };
+
+#elif defined(OVR_CPU_PPC64) || defined(OVR_CPU_PPC)
+ struct FullSync { inline FullSync() { asm volatile("sync\n"); } ~FullSync() { asm volatile("isync\n"); } };
+ struct AcquireSync { inline AcquireSync() { } ~AcquireSync() { asm volatile("isync\n"); } };
+ struct ReleaseSync { inline ReleaseSync() { asm volatile("sync\n"); } };
+
+#elif defined(OVR_CPU_MIPS)
+ struct FullSync { inline FullSync() { asm volatile("sync\n"); } ~FullSync() { asm volatile("sync\n"); } };
+ struct AcquireSync { inline AcquireSync() { } ~AcquireSync() { asm volatile("sync\n"); } };
+ struct ReleaseSync { inline ReleaseSync() { asm volatile("sync\n"); } };
+
+#elif defined(OVR_CPU_ARM)
+ struct FullSync { inline FullSync() { asm volatile("dmb\n"); } ~FullSync() { asm volatile("dmb\n"); } };
+ struct AcquireSync { inline AcquireSync() { } ~AcquireSync() { asm volatile("dmb\n"); } };
+ struct ReleaseSync { inline ReleaseSync() { asm volatile("dmb\n"); } };
+
+
+#elif defined(OVR_CC_GNU) && (__GNUC__ >= 4)
+ // __sync functions are already full sync
+ struct FullSync { inline FullSync() { } };
+ struct AcquireSync { inline AcquireSync() { } };
+ struct ReleaseSync { inline ReleaseSync() { } };
+#endif
+};
+
+
+// 4-Byte raw data atomic op implementation class.
+struct AtomicOpsRaw_4ByteImpl : public AtomicOpsRawBase
+{
+#if !defined(OVR_ENABLE_THREADS)
+
+ // Provide a type for no-thread-support cases. Used by AtomicOpsRaw_DefImpl.
+ typedef UInt32 T;
+
+ // *** Thread - Safe Atomic Versions.
+
+#elif defined(OVR_OS_WIN32)
+
+ // Use special defined for VC6, where volatile is not used and
+ // InterlockedCompareExchange is declared incorrectly.
+ typedef LONG T;
+#if defined(OVR_CC_MSVC) && (OVR_CC_MSVC < 1300)
+ typedef T* InterlockTPtr;
+ typedef LPVOID ET;
+ typedef ET* InterlockETPtr;
+#else
+ typedef volatile T* InterlockTPtr;
+ typedef T ET;
+ typedef InterlockTPtr InterlockETPtr;
+#endif
+ inline static T Exchange_NoSync(volatile T* p, T val) { return InterlockedExchange((InterlockTPtr)p, val); }
+ inline static T ExchangeAdd_NoSync(volatile T* p, T val) { return InterlockedExchangeAdd((InterlockTPtr)p, val); }
+ inline static bool CompareAndSet_NoSync(volatile T* p, T c, T val) { return InterlockedCompareExchange((InterlockETPtr)p, (ET)val, (ET)c) == (ET)c; }
+
+#elif defined(OVR_CPU_PPC64) || defined(OVR_CPU_PPC)
+ typedef UInt32 T;
+ static inline UInt32 Exchange_NoSync(volatile UInt32 *i, UInt32 j)
+ {
+ UInt32 ret;
+
+ asm volatile("1:\n\t"
+ "lwarx %[r],0,%[i]\n\t"
+ "stwcx. %[j],0,%[i]\n\t"
+ "bne- 1b\n"
+ : "+m" (*i), [r] "=&b" (ret) : [i] "b" (i), [j] "b" (j) : "cc", "memory");
+
+ return ret;
+ }
+
+ static inline UInt32 ExchangeAdd_NoSync(volatile UInt32 *i, UInt32 j)
+ {
+ UInt32 dummy, ret;
+
+ asm volatile("1:\n\t"
+ "lwarx %[r],0,%[i]\n\t"
+ "add %[o],%[r],%[j]\n\t"
+ "stwcx. %[o],0,%[i]\n\t"
+ "bne- 1b\n"
+ : "+m" (*i), [r] "=&b" (ret), [o] "=&r" (dummy) : [i] "b" (i), [j] "b" (j) : "cc", "memory");
+
+ return ret;
+ }
+
+ static inline bool CompareAndSet_NoSync(volatile UInt32 *i, UInt32 c, UInt32 value)
+ {
+ UInt32 ret;
+
+ asm volatile("1:\n\t"
+ "lwarx %[r],0,%[i]\n\t"
+ "cmpw 0,%[r],%[cmp]\n\t"
+ "mfcr %[r]\n\t"
+ "bne- 2f\n\t"
+ "stwcx. %[val],0,%[i]\n\t"
+ "bne- 1b\n\t"
+ "2:\n"
+ : "+m" (*i), [r] "=&b" (ret) : [i] "b" (i), [cmp] "b" (c), [val] "b" (value) : "cc", "memory");
+
+ return (ret & 0x20000000) ? 1 : 0;
+ }
+
+#elif defined(OVR_CPU_MIPS)
+ typedef UInt32 T;
+
+ static inline UInt32 Exchange_NoSync(volatile UInt32 *i, UInt32 j)
+ {
+ UInt32 ret;
+
+ asm volatile("1:\n\t"
+ "ll %[r],0(%[i])\n\t"
+ "sc %[j],0(%[i])\n\t"
+ "beq %[j],$0,1b\n\t"
+ "nop \n"
+ : "+m" (*i), [r] "=&d" (ret) : [i] "d" (i), [j] "d" (j) : "cc", "memory");
+
+ return ret;
+ }
+
+ static inline UInt32 ExchangeAdd_NoSync(volatile UInt32 *i, UInt32 j)
+ {
+ UInt32 ret;
+
+ asm volatile("1:\n\t"
+ "ll %[r],0(%[i])\n\t"
+ "addu %[j],%[r],%[j]\n\t"
+ "sc %[j],0(%[i])\n\t"
+ "beq %[j],$0,1b\n\t"
+ "nop \n"
+ : "+m" (*i), [r] "=&d" (ret) : [i] "d" (i), [j] "d" (j) : "cc", "memory");
+
+ return ret;
+ }
+
+ static inline bool CompareAndSet_NoSync(volatile UInt32 *i, UInt32 c, UInt32 value)
+ {
+ UInt32 ret, dummy;
+
+ asm volatile("1:\n\t"
+ "move %[r],$0\n\t"
+ "ll %[o],0(%[i])\n\t"
+ "bne %[o],%[c],2f\n\t"
+ "move %[r],%[v]\n\t"
+ "sc %[r],0(%[i])\n\t"
+ "beq %[r],$0,1b\n\t"
+ "nop \n\t"
+ "2:\n"
+ : "+m" (*i),[r] "=&d" (ret), [o] "=&d" (dummy) : [i] "d" (i), [c] "d" (c), [v] "d" (value)
+ : "cc", "memory");
+
+ return ret;
+ }
+
+#elif defined(OVR_CPU_ARM) && defined(OVR_CC_ARM)
+ typedef UInt32 T;
+
+ static inline UInt32 Exchange_NoSync(volatile UInt32 *i, UInt32 j)
+ {
+ for(;;)
+ {
+ T r = __ldrex(i);
+ if (__strex(j, i) == 0)
+ return r;
+ }
+ }
+ static inline UInt32 ExchangeAdd_NoSync(volatile UInt32 *i, UInt32 j)
+ {
+ for(;;)
+ {
+ T r = __ldrex(i);
+ if (__strex(r + j, i) == 0)
+ return r;
+ }
+ }
+
+ static inline bool CompareAndSet_NoSync(volatile UInt32 *i, UInt32 c, UInt32 value)
+ {
+ for(;;)
+ {
+ T r = __ldrex(i);
+ if (r != c)
+ return 0;
+ if (__strex(value, i) == 0)
+ return 1;
+ }
+ }
+
+#elif defined(OVR_CPU_ARM)
+ typedef UInt32 T;
+
+ static inline UInt32 Exchange_NoSync(volatile UInt32 *i, UInt32 j)
+ {
+ UInt32 ret, dummy;
+
+ asm volatile("1:\n\t"
+ "ldrex %[r],[%[i]]\n\t"
+ "strex %[t],%[j],[%[i]]\n\t"
+ "cmp %[t],#0\n\t"
+ "bne 1b\n\t"
+ : "+m" (*i), [r] "=&r" (ret), [t] "=&r" (dummy) : [i] "r" (i), [j] "r" (j) : "cc", "memory");
+
+ return ret;
+ }
+
+ static inline UInt32 ExchangeAdd_NoSync(volatile UInt32 *i, UInt32 j)
+ {
+ UInt32 ret, dummy, test;
+
+ asm volatile("1:\n\t"
+ "ldrex %[r],[%[i]]\n\t"
+ "add %[o],%[r],%[j]\n\t"
+ "strex %[t],%[o],[%[i]]\n\t"
+ "cmp %[t],#0\n\t"
+ "bne 1b\n\t"
+ : "+m" (*i), [r] "=&r" (ret), [o] "=&r" (dummy), [t] "=&r" (test) : [i] "r" (i), [j] "r" (j) : "cc", "memory");
+
+ return ret;
+ }
+
+ static inline bool CompareAndSet_NoSync(volatile UInt32 *i, UInt32 c, UInt32 value)
+ {
+ UInt32 ret = 1, dummy, test;
+
+ asm volatile("1:\n\t"
+ "ldrex %[o],[%[i]]\n\t"
+ "cmp %[o],%[c]\n\t"
+ "bne 2f\n\t"
+ "strex %[r],%[v],[%[i]]\n\t"
+ "cmp %[r],#0\n\t"
+ "bne 1b\n\t"
+ "2:\n"
+ : "+m" (*i),[r] "=&r" (ret), [o] "=&r" (dummy), [t] "=&r" (test) : [i] "r" (i), [c] "r" (c), [v] "r" (value)
+ : "cc", "memory");
+
+ return !ret;
+ }
+
+#elif defined(OVR_CPU_X86)
+ typedef UInt32 T;
+
+ static inline UInt32 Exchange_NoSync(volatile UInt32 *i, UInt32 j)
+ {
+ asm volatile("xchgl %1,%[i]\n"
+ : "+m" (*i), "=q" (j) : [i] "m" (*i), "1" (j) : "cc", "memory");
+
+ return j;
+ }
+
+ static inline UInt32 ExchangeAdd_NoSync(volatile UInt32 *i, UInt32 j)
+ {
+ asm volatile("lock; xaddl %1,%[i]\n"
+ : "+m" (*i), "+q" (j) : [i] "m" (*i) : "cc", "memory");
+
+ return j;
+ }
+
+ static inline bool CompareAndSet_NoSync(volatile UInt32 *i, UInt32 c, UInt32 value)
+ {
+ UInt32 ret;
+
+ asm volatile("lock; cmpxchgl %[v],%[i]\n"
+ : "+m" (*i), "=a" (ret) : [i] "m" (*i), "1" (c), [v] "q" (value) : "cc", "memory");
+
+ return (ret == c);
+ }
+
+#elif defined(OVR_CC_GNU) && (__GNUC__ >= 4 && __GNUC_MINOR__ >= 1)
+
+ typedef UInt32 T;
+
+ static inline T Exchange_NoSync(volatile T *i, T j)
+ {
+ T v;
+ do {
+ v = *i;
+ } while (!__sync_bool_compare_and_swap(i, v, j));
+ return v;
+ }
+
+ static inline T ExchangeAdd_NoSync(volatile T *i, T j)
+ {
+ return __sync_fetch_and_add(i, j);
+ }
+
+ static inline bool CompareAndSet_NoSync(volatile T *i, T c, T value)
+ {
+ return __sync_bool_compare_and_swap(i, c, value);
+ }
+
+#endif // OS
+};
+
+
+// 8-Byte raw data data atomic op implementation class.
+// Currently implementation is provided only on systems with 64-bit pointers.
+struct AtomicOpsRaw_8ByteImpl : public AtomicOpsRawBase
+{
+#if !defined(OVR_64BIT_POINTERS) || !defined(OVR_ENABLE_THREADS)
+
+ // Provide a type for no-thread-support cases. Used by AtomicOpsRaw_DefImpl.
+ typedef UInt64 T;
+
+ // *** Thread - Safe OS specific versions.
+#elif defined(OVR_OS_WIN32)
+
+ // This is only for 64-bit systems.
+ typedef LONG64 T;
+ typedef volatile T* InterlockTPtr;
+ inline static T Exchange_NoSync(volatile T* p, T val) { return InterlockedExchange64((InterlockTPtr)p, val); }
+ inline static T ExchangeAdd_NoSync(volatile T* p, T val) { return InterlockedExchangeAdd64((InterlockTPtr)p, val); }
+ inline static bool CompareAndSet_NoSync(volatile T* p, T c, T val) { return InterlockedCompareExchange64((InterlockTPtr)p, val, c) == c; }
+
+#elif defined(OVR_CPU_PPC64)
+
+ typedef UInt64 T;
+
+ static inline UInt64 Exchange_NoSync(volatile UInt64 *i, UInt64 j)
+ {
+ UInt64 dummy, ret;
+
+ asm volatile("1:\n\t"
+ "ldarx %[r],0,%[i]\n\t"
+ "mr %[o],%[j]\n\t"
+ "stdcx. %[o],0,%[i]\n\t"
+ "bne- 1b\n"
+ : "+m" (*i), [r] "=&b" (ret), [o] "=&r" (dummy) : [i] "b" (i), [j] "b" (j) : "cc");
+
+ return ret;
+ }
+
+ static inline UInt64 ExchangeAdd_NoSync(volatile UInt64 *i, UInt64 j)
+ {
+ UInt64 dummy, ret;
+
+ asm volatile("1:\n\t"
+ "ldarx %[r],0,%[i]\n\t"
+ "add %[o],%[r],%[j]\n\t"
+ "stdcx. %[o],0,%[i]\n\t"
+ "bne- 1b\n"
+ : "+m" (*i), [r] "=&b" (ret), [o] "=&r" (dummy) : [i] "b" (i), [j] "b" (j) : "cc");
+
+ return ret;
+ }
+
+ static inline bool CompareAndSet_NoSync(volatile UInt64 *i, UInt64 c, UInt64 value)
+ {
+ UInt64 ret, dummy;
+
+ asm volatile("1:\n\t"
+ "ldarx %[r],0,%[i]\n\t"
+ "cmpw 0,%[r],%[cmp]\n\t"
+ "mfcr %[r]\n\t"
+ "bne- 2f\n\t"
+ "stdcx. %[val],0,%[i]\n\t"
+ "bne- 1b\n\t"
+ "2:\n"
+ : "+m" (*i), [r] "=&b" (ret), [o] "=&r" (dummy) : [i] "b" (i), [cmp] "b" (c), [val] "b" (value) : "cc");
+
+ return (ret & 0x20000000) ? 1 : 0;
+ }
+
+#elif defined(OVR_CC_GNU) && (__GNUC__ >= 4 && __GNUC_MINOR__ >= 1)
+
+ typedef UInt64 T;
+
+ static inline T Exchange_NoSync(volatile T *i, T j)
+ {
+ T v;
+ do {
+ v = *i;
+ } while (!__sync_bool_compare_and_swap(i, v, j));
+ return v;
+ }
+
+ static inline T ExchangeAdd_NoSync(volatile T *i, T j)
+ {
+ return __sync_fetch_and_add(i, j);
+ }
+
+ static inline bool CompareAndSet_NoSync(volatile T *i, T c, T value)
+ {
+ return __sync_bool_compare_and_swap(i, c, value);
+ }
+
+#endif // OS
+};
+
+
+// Default implementation for AtomicOpsRaw; provides implementation of mem-fenced
+// atomic operations where fencing is done with a sync object wrapped around a NoSync
+// operation implemented in the base class. If such implementation is not possible
+// on a given platform, #ifdefs can be used to disable it and then op functions can be
+// implemented individually in the appropriate AtomicOpsRaw<size> class.
+
+template<class O>
+struct AtomicOpsRaw_DefImpl : public O
+{
+ typedef typename O::T O_T;
+ typedef typename O::FullSync O_FullSync;
+ typedef typename O::AcquireSync O_AcquireSync;
+ typedef typename O::ReleaseSync O_ReleaseSync;
+
+ // If there is no thread support, provide the default implementation. In this case,
+ // the base class (0) must still provide the T declaration.
+#ifndef OVR_ENABLE_THREADS
+
+ // Atomic exchange of val with argument. Returns old val.
+ inline static O_T Exchange_NoSync(volatile O_T* p, O_T val) { O_T old = *p; *p = val; return old; }
+ // Adds a new val to argument; returns its old val.
+ inline static O_T ExchangeAdd_NoSync(volatile O_T* p, O_T val) { O_T old = *p; *p += val; return old; }
+ // Compares the argument data with 'c' val.
+ // If succeeded, stores val int '*p' and returns true; otherwise returns false.
+ inline static bool CompareAndSet_NoSync(volatile O_T* p, O_T c, O_T val) { if (*p==c) { *p = val; return 1; } return 0; }
+
+#endif
+
+ // If NoSync wrapped implementation may not be possible, it this block should be
+ // replaced with per-function implementation in O.
+ // "AtomicOpsRaw_DefImpl<O>::" prefix in calls below.
+ inline static O_T Exchange_Sync(volatile O_T* p, O_T val) { O_FullSync sync; OVR_UNUSED(sync); return AtomicOpsRaw_DefImpl<O>::Exchange_NoSync(p, val); }
+ inline static O_T Exchange_Release(volatile O_T* p, O_T val) { O_ReleaseSync sync; OVR_UNUSED(sync); return AtomicOpsRaw_DefImpl<O>::Exchange_NoSync(p, val); }
+ inline static O_T Exchange_Acquire(volatile O_T* p, O_T val) { O_AcquireSync sync; OVR_UNUSED(sync); return AtomicOpsRaw_DefImpl<O>::Exchange_NoSync(p, val); }
+ inline static O_T ExchangeAdd_Sync(volatile O_T* p, O_T val) { O_FullSync sync; OVR_UNUSED(sync); return AtomicOpsRaw_DefImpl<O>::ExchangeAdd_NoSync(p, val); }
+ inline static O_T ExchangeAdd_Release(volatile O_T* p, O_T val) { O_ReleaseSync sync; OVR_UNUSED(sync); return AtomicOpsRaw_DefImpl<O>::ExchangeAdd_NoSync(p, val); }
+ inline static O_T ExchangeAdd_Acquire(volatile O_T* p, O_T val) { O_AcquireSync sync; OVR_UNUSED(sync); return AtomicOpsRaw_DefImpl<O>::ExchangeAdd_NoSync(p, val); }
+ inline static bool CompareAndSet_Sync(volatile O_T* p, O_T c, O_T val) { O_FullSync sync; OVR_UNUSED(sync); return AtomicOpsRaw_DefImpl<O>::CompareAndSet_NoSync(p,c,val); }
+ inline static bool CompareAndSet_Release(volatile O_T* p, O_T c, O_T val) { O_ReleaseSync sync; OVR_UNUSED(sync); return AtomicOpsRaw_DefImpl<O>::CompareAndSet_NoSync(p,c,val); }
+ inline static bool CompareAndSet_Acquire(volatile O_T* p, O_T c, O_T val) { O_AcquireSync sync; OVR_UNUSED(sync); return AtomicOpsRaw_DefImpl<O>::CompareAndSet_NoSync(p,c,val); }
+
+ // Loads and stores with memory fence. These have only the relevant versions.
+#ifdef OVR_CPU_X86
+ // On X86, Store_Release is implemented as exchange. Note that we can also
+ // consider 'sfence' in the future, although it is not as compatible with older CPUs.
+ inline static void Store_Release(volatile O_T* p, O_T val) { Exchange_Release(p, val); }
+#else
+ inline static void Store_Release(volatile O_T* p, O_T val) { O_ReleaseSync sync; OVR_UNUSED(sync); *p = val; }
+#endif
+ inline static O_T Load_Acquire(const volatile O_T* p) { O_AcquireSync sync; OVR_UNUSED(sync); return *p; }
+};
+
+
+template<int size>
+struct AtomicOpsRaw : public AtomicOpsRawBase { };
+
+template<>
+struct AtomicOpsRaw<4> : public AtomicOpsRaw_DefImpl<AtomicOpsRaw_4ByteImpl>
+{
+ // Ensure that assigned type size is correct.
+ AtomicOpsRaw()
+ { OVR_COMPILER_ASSERT(sizeof(AtomicOpsRaw_DefImpl<AtomicOpsRaw_4ByteImpl>::T) == 4); }
+};
+template<>
+struct AtomicOpsRaw<8> : public AtomicOpsRaw_DefImpl<AtomicOpsRaw_8ByteImpl>
+{
+ AtomicOpsRaw()
+ { OVR_COMPILER_ASSERT(sizeof(AtomicOpsRaw_DefImpl<AtomicOpsRaw_8ByteImpl>::T) == 8); }
+};
+
+
+// *** AtomicOps - implementation of atomic Ops for specified class
+
+// Implements atomic ops on a class, provided that the object is either
+// 4 or 8 bytes in size (depending on the AtomicOpsRaw specializations
+// available). Relies on AtomicOpsRaw for much of implementation.
+
+template<class C>
+class AtomicOps
+{
+ typedef AtomicOpsRaw<sizeof(C)> Ops;
+ typedef typename Ops::T T;
+ typedef volatile typename Ops::T* PT;
+ // We cast through unions to (1) avoid pointer size compiler warnings
+ // and (2) ensure that there are no problems with strict pointer aliasing.
+ union C2T_union { C c; T t; };
+
+public:
+ // General purpose implementation for standard syncs.
+ inline static C Exchange_Sync(volatile C* p, C val) { C2T_union u; u.c = val; u.t = Ops::Exchange_Sync((PT)p, u.t); return u.c; }
+ inline static C Exchange_Release(volatile C* p, C val) { C2T_union u; u.c = val; u.t = Ops::Exchange_Release((PT)p, u.t); return u.c; }
+ inline static C Exchange_Acquire(volatile C* p, C val) { C2T_union u; u.c = val; u.t = Ops::Exchange_Acquire((PT)p, u.t); return u.c; }
+ inline static C Exchange_NoSync(volatile C* p, C val) { C2T_union u; u.c = val; u.t = Ops::Exchange_NoSync((PT)p, u.t); return u.c; }
+ inline static C ExchangeAdd_Sync(volatile C* p, C val) { C2T_union u; u.c = val; u.t = Ops::ExchangeAdd_Sync((PT)p, u.t); return u.c; }
+ inline static C ExchangeAdd_Release(volatile C* p, C val) { C2T_union u; u.c = val; u.t = Ops::ExchangeAdd_Release((PT)p, u.t); return u.c; }
+ inline static C ExchangeAdd_Acquire(volatile C* p, C val) { C2T_union u; u.c = val; u.t = Ops::ExchangeAdd_Acquire((PT)p, u.t); return u.c; }
+ inline static C ExchangeAdd_NoSync(volatile C* p, C val) { C2T_union u; u.c = val; u.t = Ops::ExchangeAdd_NoSync((PT)p, u.t); return u.c; }
+ inline static bool CompareAndSet_Sync(volatile C* p, C c, C val) { C2T_union u,cu; u.c = val; cu.c = c; return Ops::CompareAndSet_Sync((PT)p, cu.t, u.t); }
+ inline static bool CompareAndSet_Release(volatile C* p, C c, C val){ C2T_union u,cu; u.c = val; cu.c = c; return Ops::CompareAndSet_Release((PT)p, cu.t, u.t); }
+ inline static bool CompareAndSet_Relse(volatile C* p, C c, C val){ C2T_union u,cu; u.c = val; cu.c = c; return Ops::CompareAndSet_Acquire((PT)p, cu.t, u.t); }
+ inline static bool CompareAndSet_NoSync(volatile C* p, C c, C val) { C2T_union u,cu; u.c = val; cu.c = c; return Ops::CompareAndSet_NoSync((PT)p, cu.t, u.t); }
+ // Loads and stores with memory fence. These have only the relevant versions.
+ inline static void Store_Release(volatile C* p, C val) { C2T_union u; u.c = val; Ops::Store_Release((PT)p, u.t); }
+ inline static C Load_Acquire(const volatile C* p) { C2T_union u; u.t = Ops::Load_Acquire((PT)p); return u.c; }
+};
+
+
+
+// Atomic value base class - implements operations shared for integers and pointers.
+template<class T>
+class AtomicValueBase
+{
+protected:
+ typedef AtomicOps<T> Ops;
+public:
+
+ volatile T Value;
+
+ inline AtomicValueBase() { }
+ explicit inline AtomicValueBase(T val) { Ops::Store_Release(&Value, val); }
+
+ // Most libraries (TBB and Joshua Scholar's) library do not do Load_Acquire
+ // here, since most algorithms do not require atomic loads. Needs some research.
+ inline operator T() const { return Value; }
+
+ // *** Standard Atomic inlines
+ inline T Exchange_Sync(T val) { return Ops::Exchange_Sync(&Value, val); }
+ inline T Exchange_Release(T val) { return Ops::Exchange_Release(&Value, val); }
+ inline T Exchange_Acquire(T val) { return Ops::Exchange_Acquire(&Value, val); }
+ inline T Exchange_NoSync(T val) { return Ops::Exchange_NoSync(&Value, val); }
+ inline bool CompareAndSet_Sync(T c, T val) { return Ops::CompareAndSet_Sync(&Value, c, val); }
+ inline bool CompareAndSet_Release(T c, T val) { return Ops::CompareAndSet_Release(&Value, c, val); }
+ inline bool CompareAndSet_Acquire(T c, T val) { return Ops::CompareAndSet_Relse(&Value, c, val); }
+ inline bool CompareAndSet_NoSync(T c, T val) { return Ops::CompareAndSet_NoSync(&Value, c, val); }
+ // Load & Store.
+ inline void Store_Release(T val) { Ops::Store_Release(&Value, val); }
+ inline T Load_Acquire() const { return Ops::Load_Acquire(&Value); }
+};
+
+
+// ***** AtomicPtr - Atomic pointer template
+
+// This pointer class supports atomic assignments with release,
+// increment / decrement operations, and conditional compare + set.
+
+template<class T>
+class AtomicPtr : public AtomicValueBase<T*>
+{
+ typedef typename AtomicValueBase<T*>::Ops Ops;
+
+public:
+ // Initialize pointer value to 0 by default; use Store_Release only with explicit constructor.
+ inline AtomicPtr() : AtomicValueBase<T*>() { this->Value = 0; }
+ explicit inline AtomicPtr(T* val) : AtomicValueBase<T*>(val) { }
+
+ // Pointer access.
+ inline T* operator -> () const { return this->Load_Acquire(); }
+
+ // It looks like it is convenient to have Load_Acquire characteristics
+ // for this, since that is convenient for algorithms such as linked
+ // list traversals that can be added to bu another thread.
+ inline operator T* () const { return this->Load_Acquire(); }
+
+
+ // *** Standard Atomic inlines (applicable to pointers)
+
+ // ExhangeAdd considers pointer size for pointers.
+ template<class I>
+ inline T* ExchangeAdd_Sync(I incr) { return Ops::ExchangeAdd_Sync(&this->Value, ((T*)0) + incr); }
+ template<class I>
+ inline T* ExchangeAdd_Release(I incr) { return Ops::ExchangeAdd_Release(&this->Value, ((T*)0) + incr); }
+ template<class I>
+ inline T* ExchangeAdd_Acquire(I incr) { return Ops::ExchangeAdd_Acquire(&this->Value, ((T*)0) + incr); }
+ template<class I>
+ inline T* ExchangeAdd_NoSync(I incr) { return Ops::ExchangeAdd_NoSync(&this->Value, ((T*)0) + incr); }
+
+ // *** Atomic Operators
+
+ inline T* operator = (T* val) { this->Store_Release(val); return val; }
+
+ template<class I>
+ inline T* operator += (I val) { return ExchangeAdd_Sync(val) + val; }
+ template<class I>
+ inline T* operator -= (I val) { return operator += (-val); }
+
+ inline T* operator ++ () { return ExchangeAdd_Sync(1) + 1; }
+ inline T* operator -- () { return ExchangeAdd_Sync(-1) - 1; }
+ inline T* operator ++ (int) { return ExchangeAdd_Sync(1); }
+ inline T* operator -- (int) { return ExchangeAdd_Sync(-1); }
+};
+
+
+// ***** AtomicInt - Atomic integer template
+
+// Implements an atomic integer type; the exact type to use is provided
+// as an argument. Supports atomic Acquire / Release semantics, atomic
+// arithmetic operations, and atomic conditional compare + set.
+
+template<class T>
+class AtomicInt : public AtomicValueBase<T>
+{
+ typedef typename AtomicValueBase<T>::Ops Ops;
+
+public:
+ inline AtomicInt() : AtomicValueBase<T>() { }
+ explicit inline AtomicInt(T val) : AtomicValueBase<T>(val) { }
+
+
+ // *** Standard Atomic inlines (applicable to int)
+ inline T ExchangeAdd_Sync(T val) { return Ops::ExchangeAdd_Sync(&this->Value, val); }
+ inline T ExchangeAdd_Release(T val) { return Ops::ExchangeAdd_Release(&this->Value, val); }
+ inline T ExchangeAdd_Acquire(T val) { return Ops::ExchangeAdd_Acquire(&this->Value, val); }
+ inline T ExchangeAdd_NoSync(T val) { return Ops::ExchangeAdd_NoSync(&this->Value, val); }
+ // These increments could be more efficient because they don't return a value.
+ inline void Increment_Sync() { ExchangeAdd_Sync((T)1); }
+ inline void Increment_Release() { ExchangeAdd_Release((T)1); }
+ inline void Increment_Acquire() { ExchangeAdd_Acquire((T)1); }
+ inline void Increment_NoSync() { ExchangeAdd_NoSync((T)1); }
+
+ // *** Atomic Operators
+
+ inline T operator = (T val) { this->Store_Release(val); return val; }
+ inline T operator += (T val) { return ExchangeAdd_Sync(val) + val; }
+ inline T operator -= (T val) { return ExchangeAdd_Sync(0 - val) - val; }
+
+ inline T operator ++ () { return ExchangeAdd_Sync((T)1) + 1; }
+ inline T operator -- () { return ExchangeAdd_Sync(((T)0)-1) - 1; }
+ inline T operator ++ (int) { return ExchangeAdd_Sync((T)1); }
+ inline T operator -- (int) { return ExchangeAdd_Sync(((T)0)-1); }
+
+ // More complex atomic operations. Leave it to compiler whether to optimize them or not.
+ T operator &= (T arg)
+ {
+ T comp, newVal;
+ do {
+ comp = this->Value;
+ newVal = comp & arg;
+ } while(!this->CompareAndSet_Sync(comp, newVal));
+ return newVal;
+ }
+
+ T operator |= (T arg)
+ {
+ T comp, newVal;
+ do {
+ comp = this->Value;
+ newVal = comp | arg;
+ } while(!this->CompareAndSet_Sync(comp, newVal));
+ return newVal;
+ }
+
+ T operator ^= (T arg)
+ {
+ T comp, newVal;
+ do {
+ comp = this->Value;
+ newVal = comp ^ arg;
+ } while(!this->CompareAndSet_Sync(comp, newVal));
+ return newVal;
+ }
+
+ T operator *= (T arg)
+ {
+ T comp, newVal;
+ do {
+ comp = this->Value;
+ newVal = comp * arg;
+ } while(!this->CompareAndSet_Sync(comp, newVal));
+ return newVal;
+ }
+
+ T operator /= (T arg)
+ {
+ T comp, newVal;
+ do {
+ comp = this->Value;
+ newVal = comp / arg;
+ } while(!CompareAndSet_Sync(comp, newVal));
+ return newVal;
+ }
+
+ T operator >>= (unsigned bits)
+ {
+ T comp, newVal;
+ do {
+ comp = this->Value;
+ newVal = comp >> bits;
+ } while(!CompareAndSet_Sync(comp, newVal));
+ return newVal;
+ }
+
+ T operator <<= (unsigned bits)
+ {
+ T comp, newVal;
+ do {
+ comp = this->Value;
+ newVal = comp << bits;
+ } while(!this->CompareAndSet_Sync(comp, newVal));
+ return newVal;
+ }
+};
+
+
+
+//-----------------------------------------------------------------------------------
+// ***** Lock
+
+// Lock is a simplest and most efficient mutual-exclusion lock class.
+// Unlike Mutex, it cannot be waited on.
+
+class Lock
+{
+ // NOTE: Locks are not allocatable and they themselves should not allocate
+ // memory by standard means. This is the case because StandardAllocator
+ // relies on this class.
+ // Make 'delete' private. Don't do this for 'new' since it can be redefined.
+ void operator delete(void*) {}
+
+
+ // *** Lock implementation for various platforms.
+
+#if !defined(OVR_ENABLE_THREADS)
+
+public:
+ // With no thread support, lock does nothing.
+ inline Lock() { }
+ inline Lock(unsigned) { }
+ inline ~Lock() { }
+ inline void DoLock() { }
+ inline void Unlock() { }
+
+ // Windows.
+#elif defined(OVR_OS_WIN32)
+
+ CRITICAL_SECTION cs;
+public:
+ Lock(unsigned spinCount = 0);
+ ~Lock();
+ // Locking functions.
+ inline void DoLock() { ::EnterCriticalSection(&cs); }
+ inline void Unlock() { ::LeaveCriticalSection(&cs); }
+
+#else
+ pthread_mutex_t mutex;
+
+public:
+ static pthread_mutexattr_t RecursiveAttr;
+ static bool RecursiveAttrInit;
+
+ Lock (unsigned dummy = 0)
+ {
+ if (!RecursiveAttrInit)
+ {
+ pthread_mutexattr_init(&RecursiveAttr);
+ pthread_mutexattr_settype(&RecursiveAttr, PTHREAD_MUTEX_RECURSIVE);
+ RecursiveAttrInit = 1;
+ }
+ pthread_mutex_init(&mutex,&RecursiveAttr);
+ }
+ ~Lock () { pthread_mutex_destroy(&mutex); }
+ inline void DoLock() { pthread_mutex_lock(&mutex); }
+ inline void Unlock() { pthread_mutex_unlock(&mutex); }
+
+#endif // OVR_ENABLE_THREDS
+
+
+public:
+ // Locker class, used for automatic locking
+ class Locker
+ {
+ public:
+ Lock *pLock;
+ inline Locker(Lock *plock)
+ { pLock = plock; pLock->DoLock(); }
+ inline ~Locker()
+ { pLock->Unlock(); }
+ };
+};
+
+
+
+} // OVR
+
+#endif
diff --git a/LibOVR/Src/Kernel/OVR_Color.h b/LibOVR/Src/Kernel/OVR_Color.h
index 7980d57..e05f301 100644
--- a/LibOVR/Src/Kernel/OVR_Color.h
+++ b/LibOVR/Src/Kernel/OVR_Color.h
@@ -1,55 +1,55 @@
-/************************************************************************************
-
-PublicHeader: OVR.h
-Filename : OVR_Color.h
-Content : Contains color struct.
-Created : February 7, 2013
-Notes :
-
-Copyright : Copyright 2013 Oculus VR, Inc. All Rights reserved.
-
-Use of this software is subject to the terms of the Oculus license
-agreement provided at the time of installation or download, or which
-otherwise accompanies this software in either electronic or hard copy form.
-
-************************************************************************************/
-#ifndef OVR_Color_h
-#define OVR_Color_h
-
-#include "OVR_Types.h"
-
-namespace OVR {
-
-struct Color
-{
- UByte R,G,B,A;
-
- Color() {}
-
- // Constructs color by channel. Alpha is set to 0xFF (fully visible)
- // if not specified.
- Color(unsigned char r,unsigned char g,unsigned char b, unsigned char a = 0xFF)
- : R(r), G(g), B(b), A(a) { }
-
- // 0xAARRGGBB - Common HTML color Hex layout
- Color(unsigned c)
- : R((unsigned char)(c>>16)), G((unsigned char)(c>>8)),
- B((unsigned char)c), A((unsigned char)(c>>24)) { }
-
- bool operator==(const Color& b) const
- {
- return R == b.R && G == b.G && B == b.B && A == b.A;
- }
-
- void GetRGBA(float *r, float *g, float *b, float* a) const
- {
- *r = R / 255.0f;
- *g = G / 255.0f;
- *b = B / 255.0f;
- *a = A / 255.0f;
- }
-};
-
-}
-
-#endif
+/************************************************************************************
+
+PublicHeader: OVR.h
+Filename : OVR_Color.h
+Content : Contains color struct.
+Created : February 7, 2013
+Notes :
+
+Copyright : Copyright 2013 Oculus VR, Inc. All Rights reserved.
+
+Use of this software is subject to the terms of the Oculus license
+agreement provided at the time of installation or download, or which
+otherwise accompanies this software in either electronic or hard copy form.
+
+************************************************************************************/
+#ifndef OVR_Color_h
+#define OVR_Color_h
+
+#include "OVR_Types.h"
+
+namespace OVR {
+
+struct Color
+{
+ UByte R,G,B,A;
+
+ Color() {}
+
+ // Constructs color by channel. Alpha is set to 0xFF (fully visible)
+ // if not specified.
+ Color(unsigned char r,unsigned char g,unsigned char b, unsigned char a = 0xFF)
+ : R(r), G(g), B(b), A(a) { }
+
+ // 0xAARRGGBB - Common HTML color Hex layout
+ Color(unsigned c)
+ : R((unsigned char)(c>>16)), G((unsigned char)(c>>8)),
+ B((unsigned char)c), A((unsigned char)(c>>24)) { }
+
+ bool operator==(const Color& b) const
+ {
+ return R == b.R && G == b.G && B == b.B && A == b.A;
+ }
+
+ void GetRGBA(float *r, float *g, float *b, float* a) const
+ {
+ *r = R / 255.0f;
+ *g = G / 255.0f;
+ *b = B / 255.0f;
+ *a = A / 255.0f;
+ }
+};
+
+}
+
+#endif
diff --git a/LibOVR/Src/Kernel/OVR_ContainerAllocator.h b/LibOVR/Src/Kernel/OVR_ContainerAllocator.h
index d2adf49..889bd88 100644
--- a/LibOVR/Src/Kernel/OVR_ContainerAllocator.h
+++ b/LibOVR/Src/Kernel/OVR_ContainerAllocator.h
@@ -1,256 +1,256 @@
-/************************************************************************************
-
-PublicHeader: OVR.h
-Filename : OVR_ContainerAllocator.h
-Content : Template allocators and constructors for containers.
-Created : September 19, 2012
-Notes :
-
-Copyright : Copyright 2012 Oculus VR, Inc. All Rights reserved.
-
-Use of this software is subject to the terms of the Oculus license
-agreement provided at the time of installation or download, or which
-otherwise accompanies this software in either electronic or hard copy form.
-
-************************************************************************************/
-
-#ifndef OVR_ContainerAllocator_h
-#define OVR_ContainerAllocator_h
-
-#include "OVR_Allocator.h"
-#include <string.h>
-
-
-namespace OVR {
-
-
-//-----------------------------------------------------------------------------------
-// ***** Container Allocator
-
-// ContainerAllocator serves as a template argument for allocations done by
-// containers, such as Array and Hash; replacing it could allow allocator
-// substitution in containers.
-
-class ContainerAllocatorBase
-{
-public:
- static void* Alloc(UPInt size) { return OVR_ALLOC(size); }
- static void* Realloc(void* p, UPInt newSize) { return OVR_REALLOC(p, newSize); }
- static void Free(void *p) { OVR_FREE(p); }
-};
-
-
-
-//-----------------------------------------------------------------------------------
-// ***** Constructors, Destructors, Copiers
-
-// Plain Old Data - movable, no special constructors/destructor.
-template<class T>
-class ConstructorPOD
-{
-public:
- static void Construct(void *) {}
- static void Construct(void *p, const T& source)
- {
- *(T*)p = source;
- }
-
- // Same as above, but allows for a different type of constructor.
- template <class S>
- static void ConstructAlt(void *p, const S& source)
- {
- *(T*)p = source;
- }
-
- static void ConstructArray(void*, UPInt) {}
-
- static void ConstructArray(void* p, UPInt count, const T& source)
- {
- UByte *pdata = (UByte*)p;
- for (UPInt i=0; i< count; ++i, pdata += sizeof(T))
- *(T*)pdata = source;
- }
-
- static void ConstructArray(void* p, UPInt count, const T* psource)
- {
- memcpy(p, psource, sizeof(T) * count);
- }
-
- static void Destruct(T*) {}
- static void DestructArray(T*, UPInt) {}
-
- static void CopyArrayForward(T* dst, const T* src, UPInt count)
- {
- memmove(dst, src, count * sizeof(T));
- }
-
- static void CopyArrayBackward(T* dst, const T* src, UPInt count)
- {
- memmove(dst, src, count * sizeof(T));
- }
-
- static bool IsMovable() { return true; }
-};
-
-
-//-----------------------------------------------------------------------------------
-// ***** ConstructorMov
-//
-// Correct C++ construction and destruction for movable objects
-template<class T>
-class ConstructorMov
-{
-public:
- static void Construct(void* p)
- {
- OVR::Construct<T>(p);
- }
-
- static void Construct(void* p, const T& source)
- {
- OVR::Construct<T>(p, source);
- }
-
- // Same as above, but allows for a different type of constructor.
- template <class S>
- static void ConstructAlt(void* p, const S& source)
- {
- OVR::ConstructAlt<T,S>(p, source);
- }
-
- static void ConstructArray(void* p, UPInt count)
- {
- UByte* pdata = (UByte*)p;
- for (UPInt i=0; i< count; ++i, pdata += sizeof(T))
- Construct(pdata);
- }
-
- static void ConstructArray(void* p, UPInt count, const T& source)
- {
- UByte* pdata = (UByte*)p;
- for (UPInt i=0; i< count; ++i, pdata += sizeof(T))
- Construct(pdata, source);
- }
-
- static void ConstructArray(void* p, UPInt count, const T* psource)
- {
- UByte* pdata = (UByte*)p;
- for (UPInt i=0; i< count; ++i, pdata += sizeof(T))
- Construct(pdata, *psource++);
- }
-
- static void Destruct(T* p)
- {
- p->~T();
- OVR_UNUSED(p); // Suppress silly MSVC warning
- }
-
- static void DestructArray(T* p, UPInt count)
- {
- p += count - 1;
- for (UPInt i=0; i<count; ++i, --p)
- p->~T();
- }
-
- static void CopyArrayForward(T* dst, const T* src, UPInt count)
- {
- memmove(dst, src, count * sizeof(T));
- }
-
- static void CopyArrayBackward(T* dst, const T* src, UPInt count)
- {
- memmove(dst, src, count * sizeof(T));
- }
-
- static bool IsMovable() { return true; }
-};
-
-
-//-----------------------------------------------------------------------------------
-// ***** ConstructorCPP
-//
-// Correct C++ construction and destruction for movable objects
-template<class T>
-class ConstructorCPP
-{
-public:
- static void Construct(void* p)
- {
- OVR::Construct<T>(p);
- }
-
- static void Construct(void* p, const T& source)
- {
- OVR::Construct<T>(p, source);
- }
-
- // Same as above, but allows for a different type of constructor.
- template <class S>
- static void ConstructAlt(void* p, const S& source)
- {
- OVR::ConstructAlt<T,S>(p, source);
- }
-
- static void ConstructArray(void* p, UPInt count)
- {
- UByte* pdata = (UByte*)p;
- for (UPInt i=0; i< count; ++i, pdata += sizeof(T))
- Construct(pdata);
- }
-
- static void ConstructArray(void* p, UPInt count, const T& source)
- {
- UByte* pdata = (UByte*)p;
- for (UPInt i=0; i< count; ++i, pdata += sizeof(T))
- Construct(pdata, source);
- }
-
- static void ConstructArray(void* p, UPInt count, const T* psource)
- {
- UByte* pdata = (UByte*)p;
- for (UPInt i=0; i< count; ++i, pdata += sizeof(T))
- Construct(pdata, *psource++);
- }
-
- static void Destruct(T* p)
- {
- p->~T();
- OVR_UNUSED(p); // Suppress silly MSVC warning
- }
-
- static void DestructArray(T* p, UPInt count)
- {
- p += count - 1;
- for (UPInt i=0; i<count; ++i, --p)
- p->~T();
- }
-
- static void CopyArrayForward(T* dst, const T* src, UPInt count)
- {
- for(UPInt i = 0; i < count; ++i)
- dst[i] = src[i];
- }
-
- static void CopyArrayBackward(T* dst, const T* src, UPInt count)
- {
- for(UPInt i = count; i; --i)
- dst[i-1] = src[i-1];
- }
-
- static bool IsMovable() { return false; }
-};
-
-
-//-----------------------------------------------------------------------------------
-// ***** Container Allocator with movement policy
-//
-// Simple wraps as specialized allocators
-template<class T> struct ContainerAllocator_POD : ContainerAllocatorBase, ConstructorPOD<T> {};
-template<class T> struct ContainerAllocator : ContainerAllocatorBase, ConstructorMov<T> {};
-template<class T> struct ContainerAllocator_CPP : ContainerAllocatorBase, ConstructorCPP<T> {};
-
-
-} // OVR
-
-
-#endif
+/************************************************************************************
+
+PublicHeader: OVR.h
+Filename : OVR_ContainerAllocator.h
+Content : Template allocators and constructors for containers.
+Created : September 19, 2012
+Notes :
+
+Copyright : Copyright 2012 Oculus VR, Inc. All Rights reserved.
+
+Use of this software is subject to the terms of the Oculus license
+agreement provided at the time of installation or download, or which
+otherwise accompanies this software in either electronic or hard copy form.
+
+************************************************************************************/
+
+#ifndef OVR_ContainerAllocator_h
+#define OVR_ContainerAllocator_h
+
+#include "OVR_Allocator.h"
+#include <string.h>
+
+
+namespace OVR {
+
+
+//-----------------------------------------------------------------------------------
+// ***** Container Allocator
+
+// ContainerAllocator serves as a template argument for allocations done by
+// containers, such as Array and Hash; replacing it could allow allocator
+// substitution in containers.
+
+class ContainerAllocatorBase
+{
+public:
+ static void* Alloc(UPInt size) { return OVR_ALLOC(size); }
+ static void* Realloc(void* p, UPInt newSize) { return OVR_REALLOC(p, newSize); }
+ static void Free(void *p) { OVR_FREE(p); }
+};
+
+
+
+//-----------------------------------------------------------------------------------
+// ***** Constructors, Destructors, Copiers
+
+// Plain Old Data - movable, no special constructors/destructor.
+template<class T>
+class ConstructorPOD
+{
+public:
+ static void Construct(void *) {}
+ static void Construct(void *p, const T& source)
+ {
+ *(T*)p = source;
+ }
+
+ // Same as above, but allows for a different type of constructor.
+ template <class S>
+ static void ConstructAlt(void *p, const S& source)
+ {
+ *(T*)p = source;
+ }
+
+ static void ConstructArray(void*, UPInt) {}
+
+ static void ConstructArray(void* p, UPInt count, const T& source)
+ {
+ UByte *pdata = (UByte*)p;
+ for (UPInt i=0; i< count; ++i, pdata += sizeof(T))
+ *(T*)pdata = source;
+ }
+
+ static void ConstructArray(void* p, UPInt count, const T* psource)
+ {
+ memcpy(p, psource, sizeof(T) * count);
+ }
+
+ static void Destruct(T*) {}
+ static void DestructArray(T*, UPInt) {}
+
+ static void CopyArrayForward(T* dst, const T* src, UPInt count)
+ {
+ memmove(dst, src, count * sizeof(T));
+ }
+
+ static void CopyArrayBackward(T* dst, const T* src, UPInt count)
+ {
+ memmove(dst, src, count * sizeof(T));
+ }
+
+ static bool IsMovable() { return true; }
+};
+
+
+//-----------------------------------------------------------------------------------
+// ***** ConstructorMov
+//
+// Correct C++ construction and destruction for movable objects
+template<class T>
+class ConstructorMov
+{
+public:
+ static void Construct(void* p)
+ {
+ OVR::Construct<T>(p);
+ }
+
+ static void Construct(void* p, const T& source)
+ {
+ OVR::Construct<T>(p, source);
+ }
+
+ // Same as above, but allows for a different type of constructor.
+ template <class S>
+ static void ConstructAlt(void* p, const S& source)
+ {
+ OVR::ConstructAlt<T,S>(p, source);
+ }
+
+ static void ConstructArray(void* p, UPInt count)
+ {
+ UByte* pdata = (UByte*)p;
+ for (UPInt i=0; i< count; ++i, pdata += sizeof(T))
+ Construct(pdata);
+ }
+
+ static void ConstructArray(void* p, UPInt count, const T& source)
+ {
+ UByte* pdata = (UByte*)p;
+ for (UPInt i=0; i< count; ++i, pdata += sizeof(T))
+ Construct(pdata, source);
+ }
+
+ static void ConstructArray(void* p, UPInt count, const T* psource)
+ {
+ UByte* pdata = (UByte*)p;
+ for (UPInt i=0; i< count; ++i, pdata += sizeof(T))
+ Construct(pdata, *psource++);
+ }
+
+ static void Destruct(T* p)
+ {
+ p->~T();
+ OVR_UNUSED(p); // Suppress silly MSVC warning
+ }
+
+ static void DestructArray(T* p, UPInt count)
+ {
+ p += count - 1;
+ for (UPInt i=0; i<count; ++i, --p)
+ p->~T();
+ }
+
+ static void CopyArrayForward(T* dst, const T* src, UPInt count)
+ {
+ memmove(dst, src, count * sizeof(T));
+ }
+
+ static void CopyArrayBackward(T* dst, const T* src, UPInt count)
+ {
+ memmove(dst, src, count * sizeof(T));
+ }
+
+ static bool IsMovable() { return true; }
+};
+
+
+//-----------------------------------------------------------------------------------
+// ***** ConstructorCPP
+//
+// Correct C++ construction and destruction for movable objects
+template<class T>
+class ConstructorCPP
+{
+public:
+ static void Construct(void* p)
+ {
+ OVR::Construct<T>(p);
+ }
+
+ static void Construct(void* p, const T& source)
+ {
+ OVR::Construct<T>(p, source);
+ }
+
+ // Same as above, but allows for a different type of constructor.
+ template <class S>
+ static void ConstructAlt(void* p, const S& source)
+ {
+ OVR::ConstructAlt<T,S>(p, source);
+ }
+
+ static void ConstructArray(void* p, UPInt count)
+ {
+ UByte* pdata = (UByte*)p;
+ for (UPInt i=0; i< count; ++i, pdata += sizeof(T))
+ Construct(pdata);
+ }
+
+ static void ConstructArray(void* p, UPInt count, const T& source)
+ {
+ UByte* pdata = (UByte*)p;
+ for (UPInt i=0; i< count; ++i, pdata += sizeof(T))
+ Construct(pdata, source);
+ }
+
+ static void ConstructArray(void* p, UPInt count, const T* psource)
+ {
+ UByte* pdata = (UByte*)p;
+ for (UPInt i=0; i< count; ++i, pdata += sizeof(T))
+ Construct(pdata, *psource++);
+ }
+
+ static void Destruct(T* p)
+ {
+ p->~T();
+ OVR_UNUSED(p); // Suppress silly MSVC warning
+ }
+
+ static void DestructArray(T* p, UPInt count)
+ {
+ p += count - 1;
+ for (UPInt i=0; i<count; ++i, --p)
+ p->~T();
+ }
+
+ static void CopyArrayForward(T* dst, const T* src, UPInt count)
+ {
+ for(UPInt i = 0; i < count; ++i)
+ dst[i] = src[i];
+ }
+
+ static void CopyArrayBackward(T* dst, const T* src, UPInt count)
+ {
+ for(UPInt i = count; i; --i)
+ dst[i-1] = src[i-1];
+ }
+
+ static bool IsMovable() { return false; }
+};
+
+
+//-----------------------------------------------------------------------------------
+// ***** Container Allocator with movement policy
+//
+// Simple wraps as specialized allocators
+template<class T> struct ContainerAllocator_POD : ContainerAllocatorBase, ConstructorPOD<T> {};
+template<class T> struct ContainerAllocator : ContainerAllocatorBase, ConstructorMov<T> {};
+template<class T> struct ContainerAllocator_CPP : ContainerAllocatorBase, ConstructorCPP<T> {};
+
+
+} // OVR
+
+
+#endif
diff --git a/LibOVR/Src/Kernel/OVR_File.cpp b/LibOVR/Src/Kernel/OVR_File.cpp
index 7620e37..26e94e8 100644
--- a/LibOVR/Src/Kernel/OVR_File.cpp
+++ b/LibOVR/Src/Kernel/OVR_File.cpp
@@ -1,571 +1,571 @@
-/**************************************************************************
-
-Filename : OVR_File.cpp
-Content : File wrapper class implementation (Win32)
-
-Created : April 5, 1999
-Authors : Michael Antonov
-
-Copyright : Copyright 2012 Oculus VR, Inc. All Rights reserved.
-
-Use of this software is subject to the terms of the Oculus license
-agreement provided at the time of installation or download, or which
-otherwise accompanies this software in either electronic or hard copy form.
-
-**************************************************************************/
-
-#define GFILE_CXX
-
-// Standard C library (Captain Obvious guarantees!)
-#include <stdio.h>
-
-#include "OVR_File.h"
-
-namespace OVR {
-
-// Buffered file adds buffering to an existing file
-// FILEBUFFER_SIZE defines the size of internal buffer, while
-// FILEBUFFER_TOLERANCE controls the amount of data we'll effectively try to buffer
-#define FILEBUFFER_SIZE (8192-8)
-#define FILEBUFFER_TOLERANCE 4096
-
-// ** Constructor/Destructor
-
-// Hidden constructor
-// Not supposed to be used
-BufferedFile::BufferedFile() : DelegatedFile(0)
-{
- pBuffer = (UByte*)OVR_ALLOC(FILEBUFFER_SIZE);
- BufferMode = NoBuffer;
- FilePos = 0;
- Pos = 0;
- DataSize = 0;
-}
-
-// Takes another file as source
-BufferedFile::BufferedFile(File *pfile) : DelegatedFile(pfile)
-{
- pBuffer = (UByte*)OVR_ALLOC(FILEBUFFER_SIZE);
- BufferMode = NoBuffer;
- FilePos = pfile->LTell();
- Pos = 0;
- DataSize = 0;
-}
-
-
-// Destructor
-BufferedFile::~BufferedFile()
-{
- // Flush in case there's data
- if (pFile)
- FlushBuffer();
- // Get rid of buffer
- if (pBuffer)
- OVR_FREE(pBuffer);
-}
-
-/*
-bool BufferedFile::VCopy(const Object &source)
-{
- if (!DelegatedFile::VCopy(source))
- return 0;
-
- // Data members
- BufferedFile *psource = (BufferedFile*)&source;
-
- // Buffer & the mode it's in
- pBuffer = psource->pBuffer;
- BufferMode = psource->BufferMode;
- Pos = psource->Pos;
- DataSize = psource->DataSize;
- return 1;
-}
-*/
-
-// Initializes buffering to a certain mode
-bool BufferedFile::SetBufferMode(BufferModeType mode)
-{
- if (!pBuffer)
- return false;
- if (mode == BufferMode)
- return true;
-
- FlushBuffer();
-
- // Can't set write mode if we can't write
- if ((mode==WriteBuffer) && (!pFile || !pFile->IsWritable()) )
- return 0;
-
- // And SetMode
- BufferMode = mode;
- Pos = 0;
- DataSize = 0;
- return 1;
-}
-
-// Flushes buffer
-void BufferedFile::FlushBuffer()
-{
- switch(BufferMode)
- {
- case WriteBuffer:
- // Write data in buffer
- FilePos += pFile->Write(pBuffer,Pos);
- Pos = 0;
- break;
-
- case ReadBuffer:
- // Seek back & reset buffer data
- if ((DataSize-Pos)>0)
- FilePos = pFile->LSeek(-(int)(DataSize-Pos), Seek_Cur);
- DataSize = 0;
- Pos = 0;
- break;
- default:
- // not handled!
- break;
- }
-}
-
-// Reloads data for ReadBuffer
-void BufferedFile::LoadBuffer()
-{
- if (BufferMode == ReadBuffer)
- {
- // We should only reload once all of pre-loaded buffer is consumed.
- OVR_ASSERT(Pos == DataSize);
-
- // WARNING: Right now LoadBuffer() assumes the buffer's empty
- int sz = pFile->Read(pBuffer,FILEBUFFER_SIZE);
- DataSize = sz<0 ? 0 : (unsigned)sz;
- Pos = 0;
- FilePos += DataSize;
- }
-}
-
-
-// ** Overridden functions
-
-// We override all the functions that can possibly
-// require buffer mode switch, flush, or extra calculations
-
-// Tell() requires buffer adjustment
-int BufferedFile::Tell()
-{
- if (BufferMode == ReadBuffer)
- return int (FilePos - DataSize + Pos);
-
- int pos = pFile->Tell();
- // Adjust position based on buffer mode & data
- if (pos!=-1)
- {
- OVR_ASSERT(BufferMode != ReadBuffer);
- if (BufferMode == WriteBuffer)
- pos += Pos;
- }
- return pos;
-}
-
-SInt64 BufferedFile::LTell()
-{
- if (BufferMode == ReadBuffer)
- return FilePos - DataSize + Pos;
-
- SInt64 pos = pFile->LTell();
- if (pos!=-1)
- {
- OVR_ASSERT(BufferMode != ReadBuffer);
- if (BufferMode == WriteBuffer)
- pos += Pos;
- }
- return pos;
-}
-
-int BufferedFile::GetLength()
-{
- int len = pFile->GetLength();
- // If writing through buffer, file length may actually be bigger
- if ((len!=-1) && (BufferMode==WriteBuffer))
- {
- int currPos = pFile->Tell() + Pos;
- if (currPos>len)
- len = currPos;
- }
- return len;
-}
-SInt64 BufferedFile::LGetLength()
-{
- SInt64 len = pFile->LGetLength();
- // If writing through buffer, file length may actually be bigger
- if ((len!=-1) && (BufferMode==WriteBuffer))
- {
- SInt64 currPos = pFile->LTell() + Pos;
- if (currPos>len)
- len = currPos;
- }
- return len;
-}
-
-/*
-bool BufferedFile::Stat(FileStats *pfs)
-{
- // Have to fix up length is stat
- if (pFile->Stat(pfs))
- {
- if (BufferMode==WriteBuffer)
- {
- SInt64 currPos = pFile->LTell() + Pos;
- if (currPos > pfs->Size)
- {
- pfs->Size = currPos;
- // ??
- pfs->Blocks = (pfs->Size+511) >> 9;
- }
- }
- return 1;
- }
- return 0;
-}
-*/
-
-int BufferedFile::Write(const UByte *psourceBuffer, int numBytes)
-{
- if ( (BufferMode==WriteBuffer) || SetBufferMode(WriteBuffer))
- {
- // If not data space in buffer, flush
- if ((FILEBUFFER_SIZE-(int)Pos)<numBytes)
- {
- FlushBuffer();
- // If bigger then tolerance, just write directly
- if (numBytes>FILEBUFFER_TOLERANCE)
- {
- int sz = pFile->Write(psourceBuffer,numBytes);
- if (sz > 0)
- FilePos += sz;
- return sz;
- }
- }
-
- // Enough space in buffer.. so copy to it
- memcpy(pBuffer+Pos, psourceBuffer, numBytes);
- Pos += numBytes;
- return numBytes;
- }
- int sz = pFile->Write(psourceBuffer,numBytes);
- if (sz > 0)
- FilePos += sz;
- return sz;
-}
-
-int BufferedFile::Read(UByte *pdestBuffer, int numBytes)
-{
- if ( (BufferMode==ReadBuffer) || SetBufferMode(ReadBuffer))
- {
- // Data in buffer... copy it
- if ((int)(DataSize-Pos) >= numBytes)
- {
- memcpy(pdestBuffer, pBuffer+Pos, numBytes);
- Pos += numBytes;
- return numBytes;
- }
-
- // Not enough data in buffer, copy buffer
- int readBytes = DataSize-Pos;
- memcpy(pdestBuffer, pBuffer+Pos, readBytes);
- numBytes -= readBytes;
- pdestBuffer += readBytes;
- Pos = DataSize;
-
- // Don't reload buffer if more then tolerance
- // (No major advantage, and we don't want to write a loop)
- if (numBytes>FILEBUFFER_TOLERANCE)
- {
- numBytes = pFile->Read(pdestBuffer,numBytes);
- if (numBytes > 0)
- {
- FilePos += numBytes;
- Pos = DataSize = 0;
- }
- return readBytes + ((numBytes==-1) ? 0 : numBytes);
- }
-
- // Reload the buffer
- // WARNING: Right now LoadBuffer() assumes the buffer's empty
- LoadBuffer();
- if ((int)(DataSize-Pos) < numBytes)
- numBytes = (int)DataSize-Pos;
-
- memcpy(pdestBuffer, pBuffer+Pos, numBytes);
- Pos += numBytes;
- return numBytes + readBytes;
-
- /*
- // Alternative Read implementation. The one above is probably better
- // due to FILEBUFFER_TOLERANCE.
- int total = 0;
-
- do {
- int bufferBytes = (int)(DataSize-Pos);
- int copyBytes = (bufferBytes > numBytes) ? numBytes : bufferBytes;
-
- memcpy(pdestBuffer, pBuffer+Pos, copyBytes);
- numBytes -= copyBytes;
- pdestBuffer += copyBytes;
- Pos += copyBytes;
- total += copyBytes;
-
- if (numBytes == 0)
- break;
- LoadBuffer();
-
- } while (DataSize > 0);
-
- return total;
- */
- }
- int sz = pFile->Read(pdestBuffer,numBytes);
- if (sz > 0)
- FilePos += sz;
- return sz;
-}
-
-
-int BufferedFile::SkipBytes(int numBytes)
-{
- int skippedBytes = 0;
-
- // Special case for skipping a little data in read buffer
- if (BufferMode==ReadBuffer)
- {
- skippedBytes = (((int)DataSize-(int)Pos) >= numBytes) ? numBytes : (DataSize-Pos);
- Pos += skippedBytes;
- numBytes -= skippedBytes;
- }
-
- if (numBytes)
- {
- numBytes = pFile->SkipBytes(numBytes);
- // Make sure we return the actual number skipped, or error
- if (numBytes!=-1)
- {
- skippedBytes += numBytes;
- FilePos += numBytes;
- Pos = DataSize = 0;
- }
- else if (skippedBytes <= 0)
- skippedBytes = -1;
- }
- return skippedBytes;
-}
-
-int BufferedFile::BytesAvailable()
-{
- int available = pFile->BytesAvailable();
- // Adjust available size based on buffers
- switch(BufferMode)
- {
- case ReadBuffer:
- available += DataSize-Pos;
- break;
- case WriteBuffer:
- available -= Pos;
- if (available<0)
- available= 0;
- break;
- default:
- break;
- }
- return available;
-}
-
-bool BufferedFile::Flush()
-{
- FlushBuffer();
- return pFile->Flush();
-}
-
-// Seeking could be optimized better..
-int BufferedFile::Seek(int offset, int origin)
-{
- if (BufferMode == ReadBuffer)
- {
- if (origin == Seek_Cur)
- {
- // Seek can fall either before or after Pos in the buffer,
- // but it must be within bounds.
- if (((unsigned(offset) + Pos)) <= DataSize)
- {
- Pos += offset;
- return int (FilePos - DataSize + Pos);
- }
-
- // Lightweight buffer "Flush". We do this to avoid an extra seek
- // back operation which would take place if we called FlushBuffer directly.
- origin = Seek_Set;
- OVR_ASSERT(((FilePos - DataSize + Pos) + (UInt64)offset) < ~(UInt64)0);
- offset = (int)(FilePos - DataSize + Pos) + offset;
- Pos = DataSize = 0;
- }
- else if (origin == Seek_Set)
- {
- if (((unsigned)offset - (FilePos-DataSize)) <= DataSize)
- {
- OVR_ASSERT((FilePos-DataSize) < ~(UInt64)0);
- Pos = (unsigned)offset - (unsigned)(FilePos-DataSize);
- return offset;
- }
- Pos = DataSize = 0;
- }
- else
- {
- FlushBuffer();
- }
- }
- else
- {
- FlushBuffer();
- }
-
- /*
- // Old Seek Logic
- if (origin == Seek_Cur && offset + Pos < DataSize)
- {
- //OVR_ASSERT((FilePos - DataSize) >= (FilePos - DataSize + Pos + offset));
- Pos += offset;
- OVR_ASSERT(int (Pos) >= 0);
- return int (FilePos - DataSize + Pos);
- }
- else if (origin == Seek_Set && unsigned(offset) >= FilePos - DataSize && unsigned(offset) < FilePos)
- {
- Pos = unsigned(offset - FilePos + DataSize);
- OVR_ASSERT(int (Pos) >= 0);
- return int (FilePos - DataSize + Pos);
- }
-
- FlushBuffer();
- */
-
-
- FilePos = pFile->Seek(offset,origin);
- return int (FilePos);
-}
-
-SInt64 BufferedFile::LSeek(SInt64 offset, int origin)
-{
- if (BufferMode == ReadBuffer)
- {
- if (origin == Seek_Cur)
- {
- // Seek can fall either before or after Pos in the buffer,
- // but it must be within bounds.
- if (((unsigned(offset) + Pos)) <= DataSize)
- {
- Pos += (unsigned)offset;
- return SInt64(FilePos - DataSize + Pos);
- }
-
- // Lightweight buffer "Flush". We do this to avoid an extra seek
- // back operation which would take place if we called FlushBuffer directly.
- origin = Seek_Set;
- offset = (SInt64)(FilePos - DataSize + Pos) + offset;
- Pos = DataSize = 0;
- }
- else if (origin == Seek_Set)
- {
- if (((UInt64)offset - (FilePos-DataSize)) <= DataSize)
- {
- Pos = (unsigned)((UInt64)offset - (FilePos-DataSize));
- return offset;
- }
- Pos = DataSize = 0;
- }
- else
- {
- FlushBuffer();
- }
- }
- else
- {
- FlushBuffer();
- }
-
-/*
- OVR_ASSERT(BufferMode != NoBuffer);
-
- if (origin == Seek_Cur && offset + Pos < DataSize)
- {
- Pos += int (offset);
- return FilePos - DataSize + Pos;
- }
- else if (origin == Seek_Set && offset >= SInt64(FilePos - DataSize) && offset < SInt64(FilePos))
- {
- Pos = unsigned(offset - FilePos + DataSize);
- return FilePos - DataSize + Pos;
- }
-
- FlushBuffer();
- */
-
- FilePos = pFile->LSeek(offset,origin);
- return FilePos;
-}
-
-int BufferedFile::CopyFromStream(File *pstream, int byteSize)
-{
- // We can't rely on overridden Write()
- // because delegation doesn't override virtual pointers
- // So, just re-implement
- UByte buff[0x4000];
- int count = 0;
- int szRequest, szRead, szWritten;
-
- while(byteSize)
- {
- szRequest = (byteSize > int(sizeof(buff))) ? int(sizeof(buff)) : byteSize;
-
- szRead = pstream->Read(buff,szRequest);
- szWritten = 0;
- if (szRead > 0)
- szWritten = Write(buff,szRead);
-
- count +=szWritten;
- byteSize-=szWritten;
- if (szWritten < szRequest)
- break;
- }
- return count;
-}
-
-// Closing files
-bool BufferedFile::Close()
-{
- switch(BufferMode)
- {
- case WriteBuffer:
- FlushBuffer();
- break;
- case ReadBuffer:
- // No need to seek back on close
- BufferMode = NoBuffer;
- break;
- default:
- break;
- }
- return pFile->Close();
-}
-
-
-// ***** Global path helpers
-
-// Find trailing short filename in a path.
-const char* OVR_CDECL GetShortFilename(const char* purl)
-{
- UPInt len = OVR_strlen(purl);
- for (UPInt i=len; i>0; i--)
- if (purl[i]=='\\' || purl[i]=='/')
- return purl+i+1;
- return purl;
-}
-
-} // OVR
-
+/**************************************************************************
+
+Filename : OVR_File.cpp
+Content : File wrapper class implementation (Win32)
+
+Created : April 5, 1999
+Authors : Michael Antonov
+
+Copyright : Copyright 2012 Oculus VR, Inc. All Rights reserved.
+
+Use of this software is subject to the terms of the Oculus license
+agreement provided at the time of installation or download, or which
+otherwise accompanies this software in either electronic or hard copy form.
+
+**************************************************************************/
+
+#define GFILE_CXX
+
+// Standard C library (Captain Obvious guarantees!)
+#include <stdio.h>
+
+#include "OVR_File.h"
+
+namespace OVR {
+
+// Buffered file adds buffering to an existing file
+// FILEBUFFER_SIZE defines the size of internal buffer, while
+// FILEBUFFER_TOLERANCE controls the amount of data we'll effectively try to buffer
+#define FILEBUFFER_SIZE (8192-8)
+#define FILEBUFFER_TOLERANCE 4096
+
+// ** Constructor/Destructor
+
+// Hidden constructor
+// Not supposed to be used
+BufferedFile::BufferedFile() : DelegatedFile(0)
+{
+ pBuffer = (UByte*)OVR_ALLOC(FILEBUFFER_SIZE);
+ BufferMode = NoBuffer;
+ FilePos = 0;
+ Pos = 0;
+ DataSize = 0;
+}
+
+// Takes another file as source
+BufferedFile::BufferedFile(File *pfile) : DelegatedFile(pfile)
+{
+ pBuffer = (UByte*)OVR_ALLOC(FILEBUFFER_SIZE);
+ BufferMode = NoBuffer;
+ FilePos = pfile->LTell();
+ Pos = 0;
+ DataSize = 0;
+}
+
+
+// Destructor
+BufferedFile::~BufferedFile()
+{
+ // Flush in case there's data
+ if (pFile)
+ FlushBuffer();
+ // Get rid of buffer
+ if (pBuffer)
+ OVR_FREE(pBuffer);
+}
+
+/*
+bool BufferedFile::VCopy(const Object &source)
+{
+ if (!DelegatedFile::VCopy(source))
+ return 0;
+
+ // Data members
+ BufferedFile *psource = (BufferedFile*)&source;
+
+ // Buffer & the mode it's in
+ pBuffer = psource->pBuffer;
+ BufferMode = psource->BufferMode;
+ Pos = psource->Pos;
+ DataSize = psource->DataSize;
+ return 1;
+}
+*/
+
+// Initializes buffering to a certain mode
+bool BufferedFile::SetBufferMode(BufferModeType mode)
+{
+ if (!pBuffer)
+ return false;
+ if (mode == BufferMode)
+ return true;
+
+ FlushBuffer();
+
+ // Can't set write mode if we can't write
+ if ((mode==WriteBuffer) && (!pFile || !pFile->IsWritable()) )
+ return 0;
+
+ // And SetMode
+ BufferMode = mode;
+ Pos = 0;
+ DataSize = 0;
+ return 1;
+}
+
+// Flushes buffer
+void BufferedFile::FlushBuffer()
+{
+ switch(BufferMode)
+ {
+ case WriteBuffer:
+ // Write data in buffer
+ FilePos += pFile->Write(pBuffer,Pos);
+ Pos = 0;
+ break;
+
+ case ReadBuffer:
+ // Seek back & reset buffer data
+ if ((DataSize-Pos)>0)
+ FilePos = pFile->LSeek(-(int)(DataSize-Pos), Seek_Cur);
+ DataSize = 0;
+ Pos = 0;
+ break;
+ default:
+ // not handled!
+ break;
+ }
+}
+
+// Reloads data for ReadBuffer
+void BufferedFile::LoadBuffer()
+{
+ if (BufferMode == ReadBuffer)
+ {
+ // We should only reload once all of pre-loaded buffer is consumed.
+ OVR_ASSERT(Pos == DataSize);
+
+ // WARNING: Right now LoadBuffer() assumes the buffer's empty
+ int sz = pFile->Read(pBuffer,FILEBUFFER_SIZE);
+ DataSize = sz<0 ? 0 : (unsigned)sz;
+ Pos = 0;
+ FilePos += DataSize;
+ }
+}
+
+
+// ** Overridden functions
+
+// We override all the functions that can possibly
+// require buffer mode switch, flush, or extra calculations
+
+// Tell() requires buffer adjustment
+int BufferedFile::Tell()
+{
+ if (BufferMode == ReadBuffer)
+ return int (FilePos - DataSize + Pos);
+
+ int pos = pFile->Tell();
+ // Adjust position based on buffer mode & data
+ if (pos!=-1)
+ {
+ OVR_ASSERT(BufferMode != ReadBuffer);
+ if (BufferMode == WriteBuffer)
+ pos += Pos;
+ }
+ return pos;
+}
+
+SInt64 BufferedFile::LTell()
+{
+ if (BufferMode == ReadBuffer)
+ return FilePos - DataSize + Pos;
+
+ SInt64 pos = pFile->LTell();
+ if (pos!=-1)
+ {
+ OVR_ASSERT(BufferMode != ReadBuffer);
+ if (BufferMode == WriteBuffer)
+ pos += Pos;
+ }
+ return pos;
+}
+
+int BufferedFile::GetLength()
+{
+ int len = pFile->GetLength();
+ // If writing through buffer, file length may actually be bigger
+ if ((len!=-1) && (BufferMode==WriteBuffer))
+ {
+ int currPos = pFile->Tell() + Pos;
+ if (currPos>len)
+ len = currPos;
+ }
+ return len;
+}
+SInt64 BufferedFile::LGetLength()
+{
+ SInt64 len = pFile->LGetLength();
+ // If writing through buffer, file length may actually be bigger
+ if ((len!=-1) && (BufferMode==WriteBuffer))
+ {
+ SInt64 currPos = pFile->LTell() + Pos;
+ if (currPos>len)
+ len = currPos;
+ }
+ return len;
+}
+
+/*
+bool BufferedFile::Stat(FileStats *pfs)
+{
+ // Have to fix up length is stat
+ if (pFile->Stat(pfs))
+ {
+ if (BufferMode==WriteBuffer)
+ {
+ SInt64 currPos = pFile->LTell() + Pos;
+ if (currPos > pfs->Size)
+ {
+ pfs->Size = currPos;
+ // ??
+ pfs->Blocks = (pfs->Size+511) >> 9;
+ }
+ }
+ return 1;
+ }
+ return 0;
+}
+*/
+
+int BufferedFile::Write(const UByte *psourceBuffer, int numBytes)
+{
+ if ( (BufferMode==WriteBuffer) || SetBufferMode(WriteBuffer))
+ {
+ // If not data space in buffer, flush
+ if ((FILEBUFFER_SIZE-(int)Pos)<numBytes)
+ {
+ FlushBuffer();
+ // If bigger then tolerance, just write directly
+ if (numBytes>FILEBUFFER_TOLERANCE)
+ {
+ int sz = pFile->Write(psourceBuffer,numBytes);
+ if (sz > 0)
+ FilePos += sz;
+ return sz;
+ }
+ }
+
+ // Enough space in buffer.. so copy to it
+ memcpy(pBuffer+Pos, psourceBuffer, numBytes);
+ Pos += numBytes;
+ return numBytes;
+ }
+ int sz = pFile->Write(psourceBuffer,numBytes);
+ if (sz > 0)
+ FilePos += sz;
+ return sz;
+}
+
+int BufferedFile::Read(UByte *pdestBuffer, int numBytes)
+{
+ if ( (BufferMode==ReadBuffer) || SetBufferMode(ReadBuffer))
+ {
+ // Data in buffer... copy it
+ if ((int)(DataSize-Pos) >= numBytes)
+ {
+ memcpy(pdestBuffer, pBuffer+Pos, numBytes);
+ Pos += numBytes;
+ return numBytes;
+ }
+
+ // Not enough data in buffer, copy buffer
+ int readBytes = DataSize-Pos;
+ memcpy(pdestBuffer, pBuffer+Pos, readBytes);
+ numBytes -= readBytes;
+ pdestBuffer += readBytes;
+ Pos = DataSize;
+
+ // Don't reload buffer if more then tolerance
+ // (No major advantage, and we don't want to write a loop)
+ if (numBytes>FILEBUFFER_TOLERANCE)
+ {
+ numBytes = pFile->Read(pdestBuffer,numBytes);
+ if (numBytes > 0)
+ {
+ FilePos += numBytes;
+ Pos = DataSize = 0;
+ }
+ return readBytes + ((numBytes==-1) ? 0 : numBytes);
+ }
+
+ // Reload the buffer
+ // WARNING: Right now LoadBuffer() assumes the buffer's empty
+ LoadBuffer();
+ if ((int)(DataSize-Pos) < numBytes)
+ numBytes = (int)DataSize-Pos;
+
+ memcpy(pdestBuffer, pBuffer+Pos, numBytes);
+ Pos += numBytes;
+ return numBytes + readBytes;
+
+ /*
+ // Alternative Read implementation. The one above is probably better
+ // due to FILEBUFFER_TOLERANCE.
+ int total = 0;
+
+ do {
+ int bufferBytes = (int)(DataSize-Pos);
+ int copyBytes = (bufferBytes > numBytes) ? numBytes : bufferBytes;
+
+ memcpy(pdestBuffer, pBuffer+Pos, copyBytes);
+ numBytes -= copyBytes;
+ pdestBuffer += copyBytes;
+ Pos += copyBytes;
+ total += copyBytes;
+
+ if (numBytes == 0)
+ break;
+ LoadBuffer();
+
+ } while (DataSize > 0);
+
+ return total;
+ */
+ }
+ int sz = pFile->Read(pdestBuffer,numBytes);
+ if (sz > 0)
+ FilePos += sz;
+ return sz;
+}
+
+
+int BufferedFile::SkipBytes(int numBytes)
+{
+ int skippedBytes = 0;
+
+ // Special case for skipping a little data in read buffer
+ if (BufferMode==ReadBuffer)
+ {
+ skippedBytes = (((int)DataSize-(int)Pos) >= numBytes) ? numBytes : (DataSize-Pos);
+ Pos += skippedBytes;
+ numBytes -= skippedBytes;
+ }
+
+ if (numBytes)
+ {
+ numBytes = pFile->SkipBytes(numBytes);
+ // Make sure we return the actual number skipped, or error
+ if (numBytes!=-1)
+ {
+ skippedBytes += numBytes;
+ FilePos += numBytes;
+ Pos = DataSize = 0;
+ }
+ else if (skippedBytes <= 0)
+ skippedBytes = -1;
+ }
+ return skippedBytes;
+}
+
+int BufferedFile::BytesAvailable()
+{
+ int available = pFile->BytesAvailable();
+ // Adjust available size based on buffers
+ switch(BufferMode)
+ {
+ case ReadBuffer:
+ available += DataSize-Pos;
+ break;
+ case WriteBuffer:
+ available -= Pos;
+ if (available<0)
+ available= 0;
+ break;
+ default:
+ break;
+ }
+ return available;
+}
+
+bool BufferedFile::Flush()
+{
+ FlushBuffer();
+ return pFile->Flush();
+}
+
+// Seeking could be optimized better..
+int BufferedFile::Seek(int offset, int origin)
+{
+ if (BufferMode == ReadBuffer)
+ {
+ if (origin == Seek_Cur)
+ {
+ // Seek can fall either before or after Pos in the buffer,
+ // but it must be within bounds.
+ if (((unsigned(offset) + Pos)) <= DataSize)
+ {
+ Pos += offset;
+ return int (FilePos - DataSize + Pos);
+ }
+
+ // Lightweight buffer "Flush". We do this to avoid an extra seek
+ // back operation which would take place if we called FlushBuffer directly.
+ origin = Seek_Set;
+ OVR_ASSERT(((FilePos - DataSize + Pos) + (UInt64)offset) < ~(UInt64)0);
+ offset = (int)(FilePos - DataSize + Pos) + offset;
+ Pos = DataSize = 0;
+ }
+ else if (origin == Seek_Set)
+ {
+ if (((unsigned)offset - (FilePos-DataSize)) <= DataSize)
+ {
+ OVR_ASSERT((FilePos-DataSize) < ~(UInt64)0);
+ Pos = (unsigned)offset - (unsigned)(FilePos-DataSize);
+ return offset;
+ }
+ Pos = DataSize = 0;
+ }
+ else
+ {
+ FlushBuffer();
+ }
+ }
+ else
+ {
+ FlushBuffer();
+ }
+
+ /*
+ // Old Seek Logic
+ if (origin == Seek_Cur && offset + Pos < DataSize)
+ {
+ //OVR_ASSERT((FilePos - DataSize) >= (FilePos - DataSize + Pos + offset));
+ Pos += offset;
+ OVR_ASSERT(int (Pos) >= 0);
+ return int (FilePos - DataSize + Pos);
+ }
+ else if (origin == Seek_Set && unsigned(offset) >= FilePos - DataSize && unsigned(offset) < FilePos)
+ {
+ Pos = unsigned(offset - FilePos + DataSize);
+ OVR_ASSERT(int (Pos) >= 0);
+ return int (FilePos - DataSize + Pos);
+ }
+
+ FlushBuffer();
+ */
+
+
+ FilePos = pFile->Seek(offset,origin);
+ return int (FilePos);
+}
+
+SInt64 BufferedFile::LSeek(SInt64 offset, int origin)
+{
+ if (BufferMode == ReadBuffer)
+ {
+ if (origin == Seek_Cur)
+ {
+ // Seek can fall either before or after Pos in the buffer,
+ // but it must be within bounds.
+ if (((unsigned(offset) + Pos)) <= DataSize)
+ {
+ Pos += (unsigned)offset;
+ return SInt64(FilePos - DataSize + Pos);
+ }
+
+ // Lightweight buffer "Flush". We do this to avoid an extra seek
+ // back operation which would take place if we called FlushBuffer directly.
+ origin = Seek_Set;
+ offset = (SInt64)(FilePos - DataSize + Pos) + offset;
+ Pos = DataSize = 0;
+ }
+ else if (origin == Seek_Set)
+ {
+ if (((UInt64)offset - (FilePos-DataSize)) <= DataSize)
+ {
+ Pos = (unsigned)((UInt64)offset - (FilePos-DataSize));
+ return offset;
+ }
+ Pos = DataSize = 0;
+ }
+ else
+ {
+ FlushBuffer();
+ }
+ }
+ else
+ {
+ FlushBuffer();
+ }
+
+/*
+ OVR_ASSERT(BufferMode != NoBuffer);
+
+ if (origin == Seek_Cur && offset + Pos < DataSize)
+ {
+ Pos += int (offset);
+ return FilePos - DataSize + Pos;
+ }
+ else if (origin == Seek_Set && offset >= SInt64(FilePos - DataSize) && offset < SInt64(FilePos))
+ {
+ Pos = unsigned(offset - FilePos + DataSize);
+ return FilePos - DataSize + Pos;
+ }
+
+ FlushBuffer();
+ */
+
+ FilePos = pFile->LSeek(offset,origin);
+ return FilePos;
+}
+
+int BufferedFile::CopyFromStream(File *pstream, int byteSize)
+{
+ // We can't rely on overridden Write()
+ // because delegation doesn't override virtual pointers
+ // So, just re-implement
+ UByte buff[0x4000];
+ int count = 0;
+ int szRequest, szRead, szWritten;
+
+ while(byteSize)
+ {
+ szRequest = (byteSize > int(sizeof(buff))) ? int(sizeof(buff)) : byteSize;
+
+ szRead = pstream->Read(buff,szRequest);
+ szWritten = 0;
+ if (szRead > 0)
+ szWritten = Write(buff,szRead);
+
+ count +=szWritten;
+ byteSize-=szWritten;
+ if (szWritten < szRequest)
+ break;
+ }
+ return count;
+}
+
+// Closing files
+bool BufferedFile::Close()
+{
+ switch(BufferMode)
+ {
+ case WriteBuffer:
+ FlushBuffer();
+ break;
+ case ReadBuffer:
+ // No need to seek back on close
+ BufferMode = NoBuffer;
+ break;
+ default:
+ break;
+ }
+ return pFile->Close();
+}
+
+
+// ***** Global path helpers
+
+// Find trailing short filename in a path.
+const char* OVR_CDECL GetShortFilename(const char* purl)
+{
+ UPInt len = OVR_strlen(purl);
+ for (UPInt i=len; i>0; i--)
+ if (purl[i]=='\\' || purl[i]=='/')
+ return purl+i+1;
+ return purl;
+}
+
+} // OVR
+
diff --git a/LibOVR/Src/Kernel/OVR_File.h b/LibOVR/Src/Kernel/OVR_File.h
index 262f5cf..4f7ede2 100644
--- a/LibOVR/Src/Kernel/OVR_File.h
+++ b/LibOVR/Src/Kernel/OVR_File.h
@@ -1,518 +1,518 @@
-/************************************************************************************
-
-PublicHeader: Kernel
-Filename : OVR_File.h
-Content : Header for all internal file management - functions and structures
- to be inherited by OS specific subclasses.
-Created : September 19, 2012
-Notes :
-
-Notes : errno may not be preserved across use of BaseFile member functions
- : Directories cannot be deleted while files opened from them are in use
- (For the GetFullName function)
-
-Copyright : Copyright 2012 Oculus VR, Inc. All Rights reserved.
-
-Use of this software is subject to the terms of the Oculus license
-agreement provided at the time of installation or download, or which
-otherwise accompanies this software in either electronic or hard copy form.
-
-************************************************************************************/
-
-#ifndef OVR_File_h
-#define OVR_File_h
-
-#include "OVR_RefCount.h"
-#include "OVR_Std.h"
-#include "OVR_Alg.h"
-
-#include <stdio.h>
-#include "OVR_String.h"
-
-namespace OVR {
-
-// ***** Declared classes
-class FileConstants;
-class File;
-class DelegatedFile;
-class BufferedFile;
-
-
-// ***** Flags for File & Directory accesses
-
-class FileConstants
-{
-public:
-
- // *** File open flags
- enum OpenFlags
- {
- Open_Read = 1,
- Open_Write = 2,
- Open_ReadWrite = 3,
-
- // Opens file and truncates it to zero length
- // - file must have write permission
- // - when used with Create, it opens an existing
- // file and empties it or creates a new file
- Open_Truncate = 4,
-
- // Creates and opens new file
- // - does not erase contents if file already
- // exists unless combined with Truncate
- Open_Create = 8,
-
- // Returns an error value if the file already exists
- Open_CreateOnly = 24,
-
- // Open file with buffering
- Open_Buffered = 32
- };
-
- // *** File Mode flags
- enum Modes
- {
- Mode_Read = 0444,
- Mode_Write = 0222,
- Mode_Execute = 0111,
-
- Mode_ReadWrite = 0666
- };
-
- // *** Seek operations
- enum SeekOps
- {
- Seek_Set = 0,
- Seek_Cur = 1,
- Seek_End = 2
- };
-
- // *** Errors
- enum Errors
- {
- Error_FileNotFound = 0x1001,
- Error_Access = 0x1002,
- Error_IOError = 0x1003,
- Error_DiskFull = 0x1004
- };
-};
-
-
-//-----------------------------------------------------------------------------------
-// ***** File Class
-
-// The pure virtual base random-access file
-// This is a base class to all files
-
-class File : public RefCountBase<File>, public FileConstants
-{
-public:
- File() { }
- // ** Location Information
-
- // Returns a file name path relative to the 'reference' directory
- // This is often a path that was used to create a file
- // (this is not a global path, global path can be obtained with help of directory)
- virtual const char* GetFilePath() = 0;
-
-
- // ** File Information
-
- // Return 1 if file's usable (open)
- virtual bool IsValid() = 0;
- // Return 1 if file's writable, otherwise 0
- virtual bool IsWritable() = 0;
-
- // Return position
- virtual int Tell() = 0;
- virtual SInt64 LTell() = 0;
-
- // File size
- virtual int GetLength() = 0;
- virtual SInt64 LGetLength() = 0;
-
- // Returns file stats
- // 0 for failure
- //virtual bool Stat(FileStats *pfs) = 0;
-
- // Return errno-based error code
- // Useful if any other function failed
- virtual int GetErrorCode() = 0;
-
-
- // ** Stream implementation & I/O
-
- // Blocking write, will write in the given number of bytes to the stream
- // Returns : -1 for error
- // Otherwise number of bytes read
- virtual int Write(const UByte *pbufer, int numBytes) = 0;
- // Blocking read, will read in the given number of bytes or less from the stream
- // Returns : -1 for error
- // Otherwise number of bytes read,
- // if 0 or < numBytes, no more bytes available; end of file or the other side of stream is closed
- virtual int Read(UByte *pbufer, int numBytes) = 0;
-
- // Skips (ignores) a given # of bytes
- // Same return values as Read
- virtual int SkipBytes(int numBytes) = 0;
-
- // Returns the number of bytes available to read from a stream without blocking
- // For a file, this should generally be number of bytes to the end
- virtual int BytesAvailable() = 0;
-
- // Causes any implementation's buffered data to be delivered to destination
- // Return 0 for error
- virtual bool Flush() = 0;
-
-
- // Need to provide a more optimized implementation that doe snot necessarily involve a lot of seeking
- inline bool IsEOF() { return !BytesAvailable(); }
-
-
- // Seeking
- // Returns new position, -1 for error
- virtual int Seek(int offset, int origin=Seek_Set) = 0;
- virtual SInt64 LSeek(SInt64 offset, int origin=Seek_Set) = 0;
- // Seek simplification
- int SeekToBegin() {return Seek(0); }
- int SeekToEnd() {return Seek(0,Seek_End); }
- int Skip(int numBytes) {return Seek(numBytes,Seek_Cur); }
-
-
- // Appends other file data from a stream
- // Return -1 for error, else # of bytes written
- virtual int CopyFromStream(File *pstream, int byteSize) = 0;
-
- // Closes the file
- // After close, file cannot be accessed
- virtual bool Close() = 0;
-
-
- // ***** Inlines for convenient primitive type serialization
-
- // Read/Write helpers
-private:
- UInt64 PRead64() { UInt64 v = 0; Read((UByte*)&v, 8); return v; }
- UInt32 PRead32() { UInt32 v = 0; Read((UByte*)&v, 4); return v; }
- UInt16 PRead16() { UInt16 v = 0; Read((UByte*)&v, 2); return v; }
- UByte PRead8() { UByte v = 0; Read((UByte*)&v, 1); return v; }
- void PWrite64(UInt64 v) { Write((UByte*)&v, 8); }
- void PWrite32(UInt32 v) { Write((UByte*)&v, 4); }
- void PWrite16(UInt16 v) { Write((UByte*)&v, 2); }
- void PWrite8(UByte v) { Write((UByte*)&v, 1); }
-
-public:
-
- // Writing primitive types - Little Endian
- inline void WriteUByte(UByte v) { PWrite8((UByte)Alg::ByteUtil::SystemToLE(v)); }
- inline void WriteSByte(SByte v) { PWrite8((UByte)Alg::ByteUtil::SystemToLE(v)); }
- inline void WriteUInt8(UByte v) { PWrite8((UByte)Alg::ByteUtil::SystemToLE(v)); }
- inline void WriteSInt8(SByte v) { PWrite8((UByte)Alg::ByteUtil::SystemToLE(v)); }
- inline void WriteUInt16(UInt16 v) { PWrite16((UInt16)Alg::ByteUtil::SystemToLE(v)); }
- inline void WriteSInt16(SInt16 v) { PWrite16((UInt16)Alg::ByteUtil::SystemToLE(v)); }
- inline void WriteUInt32(UInt32 v) { PWrite32((UInt32)Alg::ByteUtil::SystemToLE(v)); }
- inline void WriteSInt32(SInt32 v) { PWrite32((UInt32)Alg::ByteUtil::SystemToLE(v)); }
- inline void WriteUInt64(UInt64 v) { PWrite64((UInt64)Alg::ByteUtil::SystemToLE(v)); }
- inline void WriteSInt64(SInt64 v) { PWrite64((UInt64)Alg::ByteUtil::SystemToLE(v)); }
- inline void WriteFloat(float v) { v = Alg::ByteUtil::SystemToLE(v); Write((UByte*)&v, 4); }
- inline void WriteDouble(double v) { v = Alg::ByteUtil::SystemToLE(v); Write((UByte*)&v, 8); }
- // Writing primitive types - Big Endian
- inline void WriteUByteBE(UByte v) { PWrite8((UByte)Alg::ByteUtil::SystemToBE(v)); }
- inline void WriteSByteBE(SByte v) { PWrite8((UByte)Alg::ByteUtil::SystemToBE(v)); }
- inline void WriteUInt8BE(UInt16 v) { PWrite8((UByte)Alg::ByteUtil::SystemToBE(v)); }
- inline void WriteSInt8BE(SInt16 v) { PWrite8((UByte)Alg::ByteUtil::SystemToBE(v)); }
- inline void WriteUInt16BE(UInt16 v) { PWrite16((UInt16)Alg::ByteUtil::SystemToBE(v)); }
- inline void WriteSInt16BE(UInt16 v) { PWrite16((UInt16)Alg::ByteUtil::SystemToBE(v)); }
- inline void WriteUInt32BE(UInt32 v) { PWrite32((UInt32)Alg::ByteUtil::SystemToBE(v)); }
- inline void WriteSInt32BE(UInt32 v) { PWrite32((UInt32)Alg::ByteUtil::SystemToBE(v)); }
- inline void WriteUInt64BE(UInt64 v) { PWrite64((UInt64)Alg::ByteUtil::SystemToBE(v)); }
- inline void WriteSInt64BE(UInt64 v) { PWrite64((UInt64)Alg::ByteUtil::SystemToBE(v)); }
- inline void WriteFloatBE(float v) { v = Alg::ByteUtil::SystemToBE(v); Write((UByte*)&v, 4); }
- inline void WriteDoubleBE(double v) { v = Alg::ByteUtil::SystemToBE(v); Write((UByte*)&v, 8); }
-
- // Reading primitive types - Little Endian
- inline UByte ReadUByte() { return (UByte)Alg::ByteUtil::LEToSystem(PRead8()); }
- inline SByte ReadSByte() { return (SByte)Alg::ByteUtil::LEToSystem(PRead8()); }
- inline UByte ReadUInt8() { return (UByte)Alg::ByteUtil::LEToSystem(PRead8()); }
- inline SByte ReadSInt8() { return (SByte)Alg::ByteUtil::LEToSystem(PRead8()); }
- inline UInt16 ReadUInt16() { return (UInt16)Alg::ByteUtil::LEToSystem(PRead16()); }
- inline SInt16 ReadSInt16() { return (SInt16)Alg::ByteUtil::LEToSystem(PRead16()); }
- inline UInt32 ReadUInt32() { return (UInt32)Alg::ByteUtil::LEToSystem(PRead32()); }
- inline SInt32 ReadSInt32() { return (SInt32)Alg::ByteUtil::LEToSystem(PRead32()); }
- inline UInt64 ReadUInt64() { return (UInt64)Alg::ByteUtil::LEToSystem(PRead64()); }
- inline SInt64 ReadSInt64() { return (SInt64)Alg::ByteUtil::LEToSystem(PRead64()); }
- inline float ReadFloat() { float v = 0.0f; Read((UByte*)&v, 4); return Alg::ByteUtil::LEToSystem(v); }
- inline double ReadDouble() { double v = 0.0; Read((UByte*)&v, 8); return Alg::ByteUtil::LEToSystem(v); }
- // Reading primitive types - Big Endian
- inline UByte ReadUByteBE() { return (UByte)Alg::ByteUtil::BEToSystem(PRead8()); }
- inline SByte ReadSByteBE() { return (SByte)Alg::ByteUtil::BEToSystem(PRead8()); }
- inline UByte ReadUInt8BE() { return (UByte)Alg::ByteUtil::BEToSystem(PRead8()); }
- inline SByte ReadSInt8BE() { return (SByte)Alg::ByteUtil::BEToSystem(PRead8()); }
- inline UInt16 ReadUInt16BE() { return (UInt16)Alg::ByteUtil::BEToSystem(PRead16()); }
- inline SInt16 ReadSInt16BE() { return (SInt16)Alg::ByteUtil::BEToSystem(PRead16()); }
- inline UInt32 ReadUInt32BE() { return (UInt32)Alg::ByteUtil::BEToSystem(PRead32()); }
- inline SInt32 ReadSInt32BE() { return (SInt32)Alg::ByteUtil::BEToSystem(PRead32()); }
- inline UInt64 ReadUInt64BE() { return (UInt64)Alg::ByteUtil::BEToSystem(PRead64()); }
- inline SInt64 ReadSInt64BE() { return (SInt64)Alg::ByteUtil::BEToSystem(PRead64()); }
- inline float ReadFloatBE() { float v = 0.0f; Read((UByte*)&v, 4); return Alg::ByteUtil::BEToSystem(v); }
- inline double ReadDoubleBE() { double v = 0.0; Read((UByte*)&v, 8); return Alg::ByteUtil::BEToSystem(v); }
-};
-
-
-// *** Delegated File
-
-class DelegatedFile : public File
-{
-protected:
- // Delegating file pointer
- Ptr<File> pFile;
-
- // Hidden default constructor
- DelegatedFile() : pFile(0) { }
- DelegatedFile(const DelegatedFile &source) : File() { OVR_UNUSED(source); }
-public:
- // Constructors
- DelegatedFile(File *pfile) : pFile(pfile) { }
-
- // ** Location Information
- virtual const char* GetFilePath() { return pFile->GetFilePath(); }
-
- // ** File Information
- virtual bool IsValid() { return pFile && pFile->IsValid(); }
- virtual bool IsWritable() { return pFile->IsWritable(); }
-// virtual bool IsRecoverable() { return pFile->IsRecoverable(); }
-
- virtual int Tell() { return pFile->Tell(); }
- virtual SInt64 LTell() { return pFile->LTell(); }
-
- virtual int GetLength() { return pFile->GetLength(); }
- virtual SInt64 LGetLength() { return pFile->LGetLength(); }
-
- //virtual bool Stat(FileStats *pfs) { return pFile->Stat(pfs); }
-
- virtual int GetErrorCode() { return pFile->GetErrorCode(); }
-
- // ** Stream implementation & I/O
- virtual int Write(const UByte *pbuffer, int numBytes) { return pFile->Write(pbuffer,numBytes); }
- virtual int Read(UByte *pbuffer, int numBytes) { return pFile->Read(pbuffer,numBytes); }
-
- virtual int SkipBytes(int numBytes) { return pFile->SkipBytes(numBytes); }
-
- virtual int BytesAvailable() { return pFile->BytesAvailable(); }
-
- virtual bool Flush() { return pFile->Flush(); }
-
- // Seeking
- virtual int Seek(int offset, int origin=Seek_Set) { return pFile->Seek(offset,origin); }
- virtual SInt64 LSeek(SInt64 offset, int origin=Seek_Set) { return pFile->LSeek(offset,origin); }
-
- virtual int CopyFromStream(File *pstream, int byteSize) { return pFile->CopyFromStream(pstream,byteSize); }
-
- // Closing the file
- virtual bool Close() { return pFile->Close(); }
-};
-
-
-//-----------------------------------------------------------------------------------
-// ***** Buffered File
-
-// This file class adds buffering to an existing file
-// Buffered file never fails by itself; if there's not
-// enough memory for buffer, no buffer's used
-
-class BufferedFile : public DelegatedFile
-{
-protected:
- enum BufferModeType
- {
- NoBuffer,
- ReadBuffer,
- WriteBuffer
- };
-
- // Buffer & the mode it's in
- UByte* pBuffer;
- BufferModeType BufferMode;
- // Position in buffer
- unsigned Pos;
- // Data in buffer if reading
- unsigned DataSize;
- // Underlying file position
- UInt64 FilePos;
-
- // Initializes buffering to a certain mode
- bool SetBufferMode(BufferModeType mode);
- // Flushes buffer
- // WriteBuffer - write data to disk, ReadBuffer - reset buffer & fix file position
- void FlushBuffer();
- // Loads data into ReadBuffer
- // WARNING: Right now LoadBuffer() assumes the buffer's empty
- void LoadBuffer();
-
- // Hidden constructor
- BufferedFile();
- inline BufferedFile(const BufferedFile &source) : DelegatedFile() { OVR_UNUSED(source); }
-public:
-
- // Constructor
- // - takes another file as source
- BufferedFile(File *pfile);
- ~BufferedFile();
-
-
- // ** Overridden functions
-
- // We override all the functions that can possibly
- // require buffer mode switch, flush, or extra calculations
- virtual int Tell();
- virtual SInt64 LTell();
-
- virtual int GetLength();
- virtual SInt64 LGetLength();
-
-// virtual bool Stat(GFileStats *pfs);
-
- virtual int Write(const UByte *pbufer, int numBytes);
- virtual int Read(UByte *pbufer, int numBytes);
-
- virtual int SkipBytes(int numBytes);
-
- virtual int BytesAvailable();
-
- virtual bool Flush();
-
- virtual int Seek(int offset, int origin=Seek_Set);
- virtual SInt64 LSeek(SInt64 offset, int origin=Seek_Set);
-
- virtual int CopyFromStream(File *pstream, int byteSize);
-
- virtual bool Close();
-};
-
-
-//-----------------------------------------------------------------------------------
-// ***** Memory File
-
-class MemoryFile : public File
-{
-public:
-
- const char* GetFilePath() { return FilePath.ToCStr(); }
-
- bool IsValid() { return Valid; }
- bool IsWritable() { return false; }
-
- bool Flush() { return true; }
- int GetErrorCode() { return 0; }
-
- int Tell() { return FileIndex; }
- SInt64 LTell() { return (SInt64) FileIndex; }
-
- int GetLength() { return FileSize; }
- SInt64 LGetLength() { return (SInt64) FileSize; }
-
- bool Close()
- {
- Valid = false;
- return false;
- }
-
- int CopyFromStream(File *pstream, int byteSize)
- { OVR_UNUSED2(pstream, byteSize);
- return 0;
- }
-
- int Write(const UByte *pbuffer, int numBytes)
- { OVR_UNUSED2(pbuffer, numBytes);
- return 0;
- }
-
- int Read(UByte *pbufer, int numBytes)
- {
- if (FileIndex + numBytes > FileSize)
- {
- numBytes = FileSize - FileIndex;
- }
-
- if (numBytes > 0)
- {
- ::memcpy (pbufer, &FileData [FileIndex], numBytes);
-
- FileIndex += numBytes;
- }
-
- return numBytes;
- }
-
- int SkipBytes(int numBytes)
- {
- if (FileIndex + numBytes > FileSize)
- {
- numBytes = FileSize - FileIndex;
- }
-
- FileIndex += numBytes;
-
- return numBytes;
- }
-
- int BytesAvailable()
- {
- return (FileSize - FileIndex);
- }
-
- int Seek(int offset, int origin = Seek_Set)
- {
- switch (origin)
- {
- case Seek_Set : FileIndex = offset; break;
- case Seek_Cur : FileIndex += offset; break;
- case Seek_End : FileIndex = FileSize - offset; break;
- }
-
- return FileIndex;
- }
-
- SInt64 LSeek(SInt64 offset, int origin = Seek_Set)
- {
- return (SInt64) Seek((int) offset, origin);
- }
-
-public:
-
- MemoryFile (const String& fileName, const UByte *pBuffer, int buffSize)
- : FilePath(fileName)
- {
- FileData = pBuffer;
- FileSize = buffSize;
- FileIndex = 0;
- Valid = (!fileName.IsEmpty() && pBuffer && buffSize > 0) ? true : false;
- }
-
- // pfileName should be encoded as UTF-8 to support international file names.
- MemoryFile (const char* pfileName, const UByte *pBuffer, int buffSize)
- : FilePath(pfileName)
- {
- FileData = pBuffer;
- FileSize = buffSize;
- FileIndex = 0;
- Valid = (pfileName && pBuffer && buffSize > 0) ? true : false;
- }
-private:
-
- String FilePath;
- const UByte *FileData;
- int FileSize;
- int FileIndex;
- bool Valid;
-};
-
-
-// ***** Global path helpers
-
-// Find trailing short filename in a path.
-const char* OVR_CDECL GetShortFilename(const char* purl);
-
-} // OVR
-
-#endif
+/************************************************************************************
+
+PublicHeader: Kernel
+Filename : OVR_File.h
+Content : Header for all internal file management - functions and structures
+ to be inherited by OS specific subclasses.
+Created : September 19, 2012
+Notes :
+
+Notes : errno may not be preserved across use of BaseFile member functions
+ : Directories cannot be deleted while files opened from them are in use
+ (For the GetFullName function)
+
+Copyright : Copyright 2012 Oculus VR, Inc. All Rights reserved.
+
+Use of this software is subject to the terms of the Oculus license
+agreement provided at the time of installation or download, or which
+otherwise accompanies this software in either electronic or hard copy form.
+
+************************************************************************************/
+
+#ifndef OVR_File_h
+#define OVR_File_h
+
+#include "OVR_RefCount.h"
+#include "OVR_Std.h"
+#include "OVR_Alg.h"
+
+#include <stdio.h>
+#include "OVR_String.h"
+
+namespace OVR {
+
+// ***** Declared classes
+class FileConstants;
+class File;
+class DelegatedFile;
+class BufferedFile;
+
+
+// ***** Flags for File & Directory accesses
+
+class FileConstants
+{
+public:
+
+ // *** File open flags
+ enum OpenFlags
+ {
+ Open_Read = 1,
+ Open_Write = 2,
+ Open_ReadWrite = 3,
+
+ // Opens file and truncates it to zero length
+ // - file must have write permission
+ // - when used with Create, it opens an existing
+ // file and empties it or creates a new file
+ Open_Truncate = 4,
+
+ // Creates and opens new file
+ // - does not erase contents if file already
+ // exists unless combined with Truncate
+ Open_Create = 8,
+
+ // Returns an error value if the file already exists
+ Open_CreateOnly = 24,
+
+ // Open file with buffering
+ Open_Buffered = 32
+ };
+
+ // *** File Mode flags
+ enum Modes
+ {
+ Mode_Read = 0444,
+ Mode_Write = 0222,
+ Mode_Execute = 0111,
+
+ Mode_ReadWrite = 0666
+ };
+
+ // *** Seek operations
+ enum SeekOps
+ {
+ Seek_Set = 0,
+ Seek_Cur = 1,
+ Seek_End = 2
+ };
+
+ // *** Errors
+ enum Errors
+ {
+ Error_FileNotFound = 0x1001,
+ Error_Access = 0x1002,
+ Error_IOError = 0x1003,
+ Error_DiskFull = 0x1004
+ };
+};
+
+
+//-----------------------------------------------------------------------------------
+// ***** File Class
+
+// The pure virtual base random-access file
+// This is a base class to all files
+
+class File : public RefCountBase<File>, public FileConstants
+{
+public:
+ File() { }
+ // ** Location Information
+
+ // Returns a file name path relative to the 'reference' directory
+ // This is often a path that was used to create a file
+ // (this is not a global path, global path can be obtained with help of directory)
+ virtual const char* GetFilePath() = 0;
+
+
+ // ** File Information
+
+ // Return 1 if file's usable (open)
+ virtual bool IsValid() = 0;
+ // Return 1 if file's writable, otherwise 0
+ virtual bool IsWritable() = 0;
+
+ // Return position
+ virtual int Tell() = 0;
+ virtual SInt64 LTell() = 0;
+
+ // File size
+ virtual int GetLength() = 0;
+ virtual SInt64 LGetLength() = 0;
+
+ // Returns file stats
+ // 0 for failure
+ //virtual bool Stat(FileStats *pfs) = 0;
+
+ // Return errno-based error code
+ // Useful if any other function failed
+ virtual int GetErrorCode() = 0;
+
+
+ // ** Stream implementation & I/O
+
+ // Blocking write, will write in the given number of bytes to the stream
+ // Returns : -1 for error
+ // Otherwise number of bytes read
+ virtual int Write(const UByte *pbufer, int numBytes) = 0;
+ // Blocking read, will read in the given number of bytes or less from the stream
+ // Returns : -1 for error
+ // Otherwise number of bytes read,
+ // if 0 or < numBytes, no more bytes available; end of file or the other side of stream is closed
+ virtual int Read(UByte *pbufer, int numBytes) = 0;
+
+ // Skips (ignores) a given # of bytes
+ // Same return values as Read
+ virtual int SkipBytes(int numBytes) = 0;
+
+ // Returns the number of bytes available to read from a stream without blocking
+ // For a file, this should generally be number of bytes to the end
+ virtual int BytesAvailable() = 0;
+
+ // Causes any implementation's buffered data to be delivered to destination
+ // Return 0 for error
+ virtual bool Flush() = 0;
+
+
+ // Need to provide a more optimized implementation that doe snot necessarily involve a lot of seeking
+ inline bool IsEOF() { return !BytesAvailable(); }
+
+
+ // Seeking
+ // Returns new position, -1 for error
+ virtual int Seek(int offset, int origin=Seek_Set) = 0;
+ virtual SInt64 LSeek(SInt64 offset, int origin=Seek_Set) = 0;
+ // Seek simplification
+ int SeekToBegin() {return Seek(0); }
+ int SeekToEnd() {return Seek(0,Seek_End); }
+ int Skip(int numBytes) {return Seek(numBytes,Seek_Cur); }
+
+
+ // Appends other file data from a stream
+ // Return -1 for error, else # of bytes written
+ virtual int CopyFromStream(File *pstream, int byteSize) = 0;
+
+ // Closes the file
+ // After close, file cannot be accessed
+ virtual bool Close() = 0;
+
+
+ // ***** Inlines for convenient primitive type serialization
+
+ // Read/Write helpers
+private:
+ UInt64 PRead64() { UInt64 v = 0; Read((UByte*)&v, 8); return v; }
+ UInt32 PRead32() { UInt32 v = 0; Read((UByte*)&v, 4); return v; }
+ UInt16 PRead16() { UInt16 v = 0; Read((UByte*)&v, 2); return v; }
+ UByte PRead8() { UByte v = 0; Read((UByte*)&v, 1); return v; }
+ void PWrite64(UInt64 v) { Write((UByte*)&v, 8); }
+ void PWrite32(UInt32 v) { Write((UByte*)&v, 4); }
+ void PWrite16(UInt16 v) { Write((UByte*)&v, 2); }
+ void PWrite8(UByte v) { Write((UByte*)&v, 1); }
+
+public:
+
+ // Writing primitive types - Little Endian
+ inline void WriteUByte(UByte v) { PWrite8((UByte)Alg::ByteUtil::SystemToLE(v)); }
+ inline void WriteSByte(SByte v) { PWrite8((UByte)Alg::ByteUtil::SystemToLE(v)); }
+ inline void WriteUInt8(UByte v) { PWrite8((UByte)Alg::ByteUtil::SystemToLE(v)); }
+ inline void WriteSInt8(SByte v) { PWrite8((UByte)Alg::ByteUtil::SystemToLE(v)); }
+ inline void WriteUInt16(UInt16 v) { PWrite16((UInt16)Alg::ByteUtil::SystemToLE(v)); }
+ inline void WriteSInt16(SInt16 v) { PWrite16((UInt16)Alg::ByteUtil::SystemToLE(v)); }
+ inline void WriteUInt32(UInt32 v) { PWrite32((UInt32)Alg::ByteUtil::SystemToLE(v)); }
+ inline void WriteSInt32(SInt32 v) { PWrite32((UInt32)Alg::ByteUtil::SystemToLE(v)); }
+ inline void WriteUInt64(UInt64 v) { PWrite64((UInt64)Alg::ByteUtil::SystemToLE(v)); }
+ inline void WriteSInt64(SInt64 v) { PWrite64((UInt64)Alg::ByteUtil::SystemToLE(v)); }
+ inline void WriteFloat(float v) { v = Alg::ByteUtil::SystemToLE(v); Write((UByte*)&v, 4); }
+ inline void WriteDouble(double v) { v = Alg::ByteUtil::SystemToLE(v); Write((UByte*)&v, 8); }
+ // Writing primitive types - Big Endian
+ inline void WriteUByteBE(UByte v) { PWrite8((UByte)Alg::ByteUtil::SystemToBE(v)); }
+ inline void WriteSByteBE(SByte v) { PWrite8((UByte)Alg::ByteUtil::SystemToBE(v)); }
+ inline void WriteUInt8BE(UInt16 v) { PWrite8((UByte)Alg::ByteUtil::SystemToBE(v)); }
+ inline void WriteSInt8BE(SInt16 v) { PWrite8((UByte)Alg::ByteUtil::SystemToBE(v)); }
+ inline void WriteUInt16BE(UInt16 v) { PWrite16((UInt16)Alg::ByteUtil::SystemToBE(v)); }
+ inline void WriteSInt16BE(UInt16 v) { PWrite16((UInt16)Alg::ByteUtil::SystemToBE(v)); }
+ inline void WriteUInt32BE(UInt32 v) { PWrite32((UInt32)Alg::ByteUtil::SystemToBE(v)); }
+ inline void WriteSInt32BE(UInt32 v) { PWrite32((UInt32)Alg::ByteUtil::SystemToBE(v)); }
+ inline void WriteUInt64BE(UInt64 v) { PWrite64((UInt64)Alg::ByteUtil::SystemToBE(v)); }
+ inline void WriteSInt64BE(UInt64 v) { PWrite64((UInt64)Alg::ByteUtil::SystemToBE(v)); }
+ inline void WriteFloatBE(float v) { v = Alg::ByteUtil::SystemToBE(v); Write((UByte*)&v, 4); }
+ inline void WriteDoubleBE(double v) { v = Alg::ByteUtil::SystemToBE(v); Write((UByte*)&v, 8); }
+
+ // Reading primitive types - Little Endian
+ inline UByte ReadUByte() { return (UByte)Alg::ByteUtil::LEToSystem(PRead8()); }
+ inline SByte ReadSByte() { return (SByte)Alg::ByteUtil::LEToSystem(PRead8()); }
+ inline UByte ReadUInt8() { return (UByte)Alg::ByteUtil::LEToSystem(PRead8()); }
+ inline SByte ReadSInt8() { return (SByte)Alg::ByteUtil::LEToSystem(PRead8()); }
+ inline UInt16 ReadUInt16() { return (UInt16)Alg::ByteUtil::LEToSystem(PRead16()); }
+ inline SInt16 ReadSInt16() { return (SInt16)Alg::ByteUtil::LEToSystem(PRead16()); }
+ inline UInt32 ReadUInt32() { return (UInt32)Alg::ByteUtil::LEToSystem(PRead32()); }
+ inline SInt32 ReadSInt32() { return (SInt32)Alg::ByteUtil::LEToSystem(PRead32()); }
+ inline UInt64 ReadUInt64() { return (UInt64)Alg::ByteUtil::LEToSystem(PRead64()); }
+ inline SInt64 ReadSInt64() { return (SInt64)Alg::ByteUtil::LEToSystem(PRead64()); }
+ inline float ReadFloat() { float v = 0.0f; Read((UByte*)&v, 4); return Alg::ByteUtil::LEToSystem(v); }
+ inline double ReadDouble() { double v = 0.0; Read((UByte*)&v, 8); return Alg::ByteUtil::LEToSystem(v); }
+ // Reading primitive types - Big Endian
+ inline UByte ReadUByteBE() { return (UByte)Alg::ByteUtil::BEToSystem(PRead8()); }
+ inline SByte ReadSByteBE() { return (SByte)Alg::ByteUtil::BEToSystem(PRead8()); }
+ inline UByte ReadUInt8BE() { return (UByte)Alg::ByteUtil::BEToSystem(PRead8()); }
+ inline SByte ReadSInt8BE() { return (SByte)Alg::ByteUtil::BEToSystem(PRead8()); }
+ inline UInt16 ReadUInt16BE() { return (UInt16)Alg::ByteUtil::BEToSystem(PRead16()); }
+ inline SInt16 ReadSInt16BE() { return (SInt16)Alg::ByteUtil::BEToSystem(PRead16()); }
+ inline UInt32 ReadUInt32BE() { return (UInt32)Alg::ByteUtil::BEToSystem(PRead32()); }
+ inline SInt32 ReadSInt32BE() { return (SInt32)Alg::ByteUtil::BEToSystem(PRead32()); }
+ inline UInt64 ReadUInt64BE() { return (UInt64)Alg::ByteUtil::BEToSystem(PRead64()); }
+ inline SInt64 ReadSInt64BE() { return (SInt64)Alg::ByteUtil::BEToSystem(PRead64()); }
+ inline float ReadFloatBE() { float v = 0.0f; Read((UByte*)&v, 4); return Alg::ByteUtil::BEToSystem(v); }
+ inline double ReadDoubleBE() { double v = 0.0; Read((UByte*)&v, 8); return Alg::ByteUtil::BEToSystem(v); }
+};
+
+
+// *** Delegated File
+
+class DelegatedFile : public File
+{
+protected:
+ // Delegating file pointer
+ Ptr<File> pFile;
+
+ // Hidden default constructor
+ DelegatedFile() : pFile(0) { }
+ DelegatedFile(const DelegatedFile &source) : File() { OVR_UNUSED(source); }
+public:
+ // Constructors
+ DelegatedFile(File *pfile) : pFile(pfile) { }
+
+ // ** Location Information
+ virtual const char* GetFilePath() { return pFile->GetFilePath(); }
+
+ // ** File Information
+ virtual bool IsValid() { return pFile && pFile->IsValid(); }
+ virtual bool IsWritable() { return pFile->IsWritable(); }
+// virtual bool IsRecoverable() { return pFile->IsRecoverable(); }
+
+ virtual int Tell() { return pFile->Tell(); }
+ virtual SInt64 LTell() { return pFile->LTell(); }
+
+ virtual int GetLength() { return pFile->GetLength(); }
+ virtual SInt64 LGetLength() { return pFile->LGetLength(); }
+
+ //virtual bool Stat(FileStats *pfs) { return pFile->Stat(pfs); }
+
+ virtual int GetErrorCode() { return pFile->GetErrorCode(); }
+
+ // ** Stream implementation & I/O
+ virtual int Write(const UByte *pbuffer, int numBytes) { return pFile->Write(pbuffer,numBytes); }
+ virtual int Read(UByte *pbuffer, int numBytes) { return pFile->Read(pbuffer,numBytes); }
+
+ virtual int SkipBytes(int numBytes) { return pFile->SkipBytes(numBytes); }
+
+ virtual int BytesAvailable() { return pFile->BytesAvailable(); }
+
+ virtual bool Flush() { return pFile->Flush(); }
+
+ // Seeking
+ virtual int Seek(int offset, int origin=Seek_Set) { return pFile->Seek(offset,origin); }
+ virtual SInt64 LSeek(SInt64 offset, int origin=Seek_Set) { return pFile->LSeek(offset,origin); }
+
+ virtual int CopyFromStream(File *pstream, int byteSize) { return pFile->CopyFromStream(pstream,byteSize); }
+
+ // Closing the file
+ virtual bool Close() { return pFile->Close(); }
+};
+
+
+//-----------------------------------------------------------------------------------
+// ***** Buffered File
+
+// This file class adds buffering to an existing file
+// Buffered file never fails by itself; if there's not
+// enough memory for buffer, no buffer's used
+
+class BufferedFile : public DelegatedFile
+{
+protected:
+ enum BufferModeType
+ {
+ NoBuffer,
+ ReadBuffer,
+ WriteBuffer
+ };
+
+ // Buffer & the mode it's in
+ UByte* pBuffer;
+ BufferModeType BufferMode;
+ // Position in buffer
+ unsigned Pos;
+ // Data in buffer if reading
+ unsigned DataSize;
+ // Underlying file position
+ UInt64 FilePos;
+
+ // Initializes buffering to a certain mode
+ bool SetBufferMode(BufferModeType mode);
+ // Flushes buffer
+ // WriteBuffer - write data to disk, ReadBuffer - reset buffer & fix file position
+ void FlushBuffer();
+ // Loads data into ReadBuffer
+ // WARNING: Right now LoadBuffer() assumes the buffer's empty
+ void LoadBuffer();
+
+ // Hidden constructor
+ BufferedFile();
+ inline BufferedFile(const BufferedFile &source) : DelegatedFile() { OVR_UNUSED(source); }
+public:
+
+ // Constructor
+ // - takes another file as source
+ BufferedFile(File *pfile);
+ ~BufferedFile();
+
+
+ // ** Overridden functions
+
+ // We override all the functions that can possibly
+ // require buffer mode switch, flush, or extra calculations
+ virtual int Tell();
+ virtual SInt64 LTell();
+
+ virtual int GetLength();
+ virtual SInt64 LGetLength();
+
+// virtual bool Stat(GFileStats *pfs);
+
+ virtual int Write(const UByte *pbufer, int numBytes);
+ virtual int Read(UByte *pbufer, int numBytes);
+
+ virtual int SkipBytes(int numBytes);
+
+ virtual int BytesAvailable();
+
+ virtual bool Flush();
+
+ virtual int Seek(int offset, int origin=Seek_Set);
+ virtual SInt64 LSeek(SInt64 offset, int origin=Seek_Set);
+
+ virtual int CopyFromStream(File *pstream, int byteSize);
+
+ virtual bool Close();
+};
+
+
+//-----------------------------------------------------------------------------------
+// ***** Memory File
+
+class MemoryFile : public File
+{
+public:
+
+ const char* GetFilePath() { return FilePath.ToCStr(); }
+
+ bool IsValid() { return Valid; }
+ bool IsWritable() { return false; }
+
+ bool Flush() { return true; }
+ int GetErrorCode() { return 0; }
+
+ int Tell() { return FileIndex; }
+ SInt64 LTell() { return (SInt64) FileIndex; }
+
+ int GetLength() { return FileSize; }
+ SInt64 LGetLength() { return (SInt64) FileSize; }
+
+ bool Close()
+ {
+ Valid = false;
+ return false;
+ }
+
+ int CopyFromStream(File *pstream, int byteSize)
+ { OVR_UNUSED2(pstream, byteSize);
+ return 0;
+ }
+
+ int Write(const UByte *pbuffer, int numBytes)
+ { OVR_UNUSED2(pbuffer, numBytes);
+ return 0;
+ }
+
+ int Read(UByte *pbufer, int numBytes)
+ {
+ if (FileIndex + numBytes > FileSize)
+ {
+ numBytes = FileSize - FileIndex;
+ }
+
+ if (numBytes > 0)
+ {
+ ::memcpy (pbufer, &FileData [FileIndex], numBytes);
+
+ FileIndex += numBytes;
+ }
+
+ return numBytes;
+ }
+
+ int SkipBytes(int numBytes)
+ {
+ if (FileIndex + numBytes > FileSize)
+ {
+ numBytes = FileSize - FileIndex;
+ }
+
+ FileIndex += numBytes;
+
+ return numBytes;
+ }
+
+ int BytesAvailable()
+ {
+ return (FileSize - FileIndex);
+ }
+
+ int Seek(int offset, int origin = Seek_Set)
+ {
+ switch (origin)
+ {
+ case Seek_Set : FileIndex = offset; break;
+ case Seek_Cur : FileIndex += offset; break;
+ case Seek_End : FileIndex = FileSize - offset; break;
+ }
+
+ return FileIndex;
+ }
+
+ SInt64 LSeek(SInt64 offset, int origin = Seek_Set)
+ {
+ return (SInt64) Seek((int) offset, origin);
+ }
+
+public:
+
+ MemoryFile (const String& fileName, const UByte *pBuffer, int buffSize)
+ : FilePath(fileName)
+ {
+ FileData = pBuffer;
+ FileSize = buffSize;
+ FileIndex = 0;
+ Valid = (!fileName.IsEmpty() && pBuffer && buffSize > 0) ? true : false;
+ }
+
+ // pfileName should be encoded as UTF-8 to support international file names.
+ MemoryFile (const char* pfileName, const UByte *pBuffer, int buffSize)
+ : FilePath(pfileName)
+ {
+ FileData = pBuffer;
+ FileSize = buffSize;
+ FileIndex = 0;
+ Valid = (pfileName && pBuffer && buffSize > 0) ? true : false;
+ }
+private:
+
+ String FilePath;
+ const UByte *FileData;
+ int FileSize;
+ int FileIndex;
+ bool Valid;
+};
+
+
+// ***** Global path helpers
+
+// Find trailing short filename in a path.
+const char* OVR_CDECL GetShortFilename(const char* purl);
+
+} // OVR
+
+#endif
diff --git a/LibOVR/Src/Kernel/OVR_FileFILE.cpp b/LibOVR/Src/Kernel/OVR_FileFILE.cpp
index 4ee32b6..dd77fde 100644
--- a/LibOVR/Src/Kernel/OVR_FileFILE.cpp
+++ b/LibOVR/Src/Kernel/OVR_FileFILE.cpp
@@ -1,583 +1,583 @@
-/**************************************************************************
-
-Filename : OVR_FileFILE.cpp
-Content : File wrapper class implementation (Win32)
-
-Created : April 5, 1999
-Authors : Michael Antonov
-
-Copyright : Copyright 2012 Oculus VR, Inc. All Rights reserved.
-
-Use of this software is subject to the terms of the Oculus license
-agreement provided at the time of installation or download, or which
-otherwise accompanies this software in either electronic or hard copy form.
-
-**************************************************************************/
-
-#define GFILE_CXX
-
-#include "OVR_Types.h"
-#include "OVR_Log.h"
-
-// Standard C library (Captain Obvious guarantees!)
-#include <stdio.h>
-#ifndef OVR_OS_WINCE
-#include <sys/stat.h>
-#endif
-
-#include "OVR_SysFile.h"
-
-#ifndef OVR_OS_WINCE
-#include <errno.h>
-#endif
-
-namespace OVR {
-
-// ***** File interface
-
-// ***** FILEFile - C streams file
-
-static int SFerror ()
-{
- if (errno == ENOENT)
- return FileConstants::Error_FileNotFound;
- else if (errno == EACCES || errno == EPERM)
- return FileConstants::Error_Access;
- else if (errno == ENOSPC)
- return FileConstants::Error_DiskFull;
- else
- return FileConstants::Error_IOError;
-};
-
-#ifdef OVR_OS_WIN32
-#include "windows.h"
-// A simple helper class to disable/enable system error mode, if necessary
-// Disabling happens conditionally only if a drive name is involved
-class SysErrorModeDisabler
-{
- BOOL Disabled;
- UINT OldMode;
-public:
- SysErrorModeDisabler(const char* pfileName)
- {
- if (pfileName && (pfileName[0]!=0) && pfileName[1]==':')
- {
- Disabled = 1;
- OldMode = ::SetErrorMode(SEM_FAILCRITICALERRORS);
- }
- else
- Disabled = 0;
- }
-
- ~SysErrorModeDisabler()
- {
- if (Disabled) ::SetErrorMode(OldMode);
- }
-};
-#else
-class SysErrorModeDisabler
-{
-public:
- SysErrorModeDisabler(const char* pfileName) { }
-};
-#endif // OVR_OS_WIN32
-
-
-// This macro enables verification of I/O results after seeks against a pre-loaded
-// full file buffer copy. This is generally not necessary, but can been used to debug
-// memory corruptions; we've seen this fail due to EAX2/DirectSound corrupting memory
-// under FMOD with XP64 (32-bit) and Realtek HA Audio driver.
-//#define GFILE_VERIFY_SEEK_ERRORS
-
-
-// This is the simplest possible file implementation, it wraps around the descriptor
-// This file is delegated to by SysFile.
-
-class FILEFile : public File
-{
-protected:
-
- // Allocated filename
- String FileName;
-
- // File handle & open mode
- bool Opened;
- FILE* fs;
- int OpenFlags;
- // Error code for last request
- int ErrorCode;
-
- int LastOp;
-
-#ifdef OVR_FILE_VERIFY_SEEK_ERRORS
- UByte* pFileTestBuffer;
- unsigned FileTestLength;
- unsigned TestPos; // File pointer position during tests.
-#endif
-
-public:
-
- FILEFile()
- {
- Opened = 0; FileName = "";
-
-#ifdef OVR_FILE_VERIFY_SEEK_ERRORS
- pFileTestBuffer =0;
- FileTestLength =0;
- TestPos =0;
-#endif
- }
- // Initialize file by opening it
- FILEFile(const String& fileName, int flags, int Mode);
- // The 'pfileName' should be encoded as UTF-8 to support international file names.
- FILEFile(const char* pfileName, int flags, int Mode);
-
- ~FILEFile()
- {
- if (Opened)
- Close();
- }
-
- virtual const char* GetFilePath();
-
- // ** File Information
- virtual bool IsValid();
- virtual bool IsWritable();
-
- // Return position / file size
- virtual int Tell();
- virtual SInt64 LTell();
- virtual int GetLength();
- virtual SInt64 LGetLength();
-
-// virtual bool Stat(FileStats *pfs);
- virtual int GetErrorCode();
-
- // ** Stream implementation & I/O
- virtual int Write(const UByte *pbuffer, int numBytes);
- virtual int Read(UByte *pbuffer, int numBytes);
- virtual int SkipBytes(int numBytes);
- virtual int BytesAvailable();
- virtual bool Flush();
- virtual int Seek(int offset, int origin);
- virtual SInt64 LSeek(SInt64 offset, int origin);
-
- virtual int CopyFromStream(File *pStream, int byteSize);
- virtual bool Close();
-private:
- void init();
-};
-
-
-// Initialize file by opening it
-FILEFile::FILEFile(const String& fileName, int flags, int mode)
- : FileName(fileName), OpenFlags(flags)
-{
- OVR_UNUSED(mode);
- init();
-}
-
-// The 'pfileName' should be encoded as UTF-8 to support international file names.
-FILEFile::FILEFile(const char* pfileName, int flags, int mode)
- : FileName(pfileName), OpenFlags(flags)
-{
- OVR_UNUSED(mode);
- init();
-}
-
-void FILEFile::init()
-{
- // Open mode for file's open
- const char *omode = "rb";
-
- if (OpenFlags & Open_Truncate)
- {
- if (OpenFlags & Open_Read)
- omode = "w+b";
- else
- omode = "wb";
- }
- else if (OpenFlags & Open_Create)
- {
- if (OpenFlags & Open_Read)
- omode = "a+b";
- else
- omode = "ab";
- }
- else if (OpenFlags & Open_Write)
- omode = "r+b";
-
-#ifdef OVR_OS_WIN32
- SysErrorModeDisabler disabler(FileName.ToCStr());
-#endif
-
-#if defined(OVR_CC_MSVC) && (OVR_CC_MSVC >= 1400)
- wchar_t womode[16];
- wchar_t *pwFileName = (wchar_t*)OVR_ALLOC((UTF8Util::GetLength(FileName.ToCStr())+1) * sizeof(wchar_t));
- UTF8Util::DecodeString(pwFileName, FileName.ToCStr());
- OVR_ASSERT(strlen(omode) < sizeof(womode)/sizeof(womode[0]));
- UTF8Util::DecodeString(womode, omode);
- _wfopen_s(&fs, pwFileName, womode);
- OVR_FREE(pwFileName);
-#else
- fs = fopen(FileName.ToCStr(), omode);
-#endif
- if (fs)
- rewind (fs);
- Opened = (fs != NULL);
- // Set error code
- if (!Opened)
- ErrorCode = SFerror();
- else
- {
- // If we are testing file seek correctness, pre-load the entire file so
- // that we can do comparison tests later.
-#ifdef OVR_FILE_VERIFY_SEEK_ERRORS
- TestPos = 0;
- fseek(fs, 0, SEEK_END);
- FileTestLength = ftell(fs);
- fseek(fs, 0, SEEK_SET);
- pFileTestBuffer = (UByte*)OVR_ALLOC(FileTestLength);
- if (pFileTestBuffer)
- {
- OVR_ASSERT(FileTestLength == (unsigned)Read(pFileTestBuffer, FileTestLength));
- Seek(0, Seek_Set);
- }
-#endif
-
- ErrorCode = 0;
- }
- LastOp = 0;
-}
-
-
-const char* FILEFile::GetFilePath()
-{
- return FileName.ToCStr();
-}
-
-
-// ** File Information
-bool FILEFile::IsValid()
-{
- return Opened;
-}
-bool FILEFile::IsWritable()
-{
- return IsValid() && (OpenFlags&Open_Write);
-}
-/*
-bool FILEFile::IsRecoverable()
-{
- return IsValid() && ((OpenFlags&OVR_FO_SAFETRUNC) == OVR_FO_SAFETRUNC);
-}
-*/
-
-// Return position / file size
-int FILEFile::Tell()
-{
- int pos = (int)ftell (fs);
- if (pos < 0)
- ErrorCode = SFerror();
- return pos;
-}
-
-SInt64 FILEFile::LTell()
-{
- SInt64 pos = ftell(fs);
- if (pos < 0)
- ErrorCode = SFerror();
- return pos;
-}
-
-int FILEFile::GetLength()
-{
- int pos = Tell();
- if (pos >= 0)
- {
- Seek (0, Seek_End);
- int size = Tell();
- Seek (pos, Seek_Set);
- return size;
- }
- return -1;
-}
-SInt64 FILEFile::LGetLength()
-{
- SInt64 pos = LTell();
- if (pos >= 0)
- {
- LSeek (0, Seek_End);
- SInt64 size = LTell();
- LSeek (pos, Seek_Set);
- return size;
- }
- return -1;
-}
-
-int FILEFile::GetErrorCode()
-{
- return ErrorCode;
-}
-
-// ** Stream implementation & I/O
-int FILEFile::Write(const UByte *pbuffer, int numBytes)
-{
- if (LastOp && LastOp != Open_Write)
- fflush(fs);
- LastOp = Open_Write;
- int written = (int) fwrite(pbuffer, 1, numBytes, fs);
- if (written < numBytes)
- ErrorCode = SFerror();
-
-#ifdef OVR_FILE_VERIFY_SEEK_ERRORS
- if (written > 0)
- TestPos += written;
-#endif
-
- return written;
-}
-
-int FILEFile::Read(UByte *pbuffer, int numBytes)
-{
- if (LastOp && LastOp != Open_Read)
- fflush(fs);
- LastOp = Open_Read;
- int read = (int) fread(pbuffer, 1, numBytes, fs);
- if (read < numBytes)
- ErrorCode = SFerror();
-
-#ifdef OVR_FILE_VERIFY_SEEK_ERRORS
- if (read > 0)
- {
- // Read-in data must match our pre-loaded buffer data!
- UByte* pcompareBuffer = pFileTestBuffer + TestPos;
- for (int i=0; i< read; i++)
- {
- OVR_ASSERT(pcompareBuffer[i] == pbuffer[i]);
- }
-
- //OVR_ASSERT(!memcmp(pFileTestBuffer + TestPos, pbuffer, read));
- TestPos += read;
- OVR_ASSERT(ftell(fs) == (int)TestPos);
- }
-#endif
-
- return read;
-}
-
-// Seeks ahead to skip bytes
-int FILEFile::SkipBytes(int numBytes)
-{
- SInt64 pos = LTell();
- SInt64 newPos = LSeek(numBytes, Seek_Cur);
-
- // Return -1 for major error
- if ((pos==-1) || (newPos==-1))
- {
- return -1;
- }
- //ErrorCode = ((NewPos-Pos)<numBytes) ? errno : 0;
-
- return int (newPos-(int)pos);
-}
-
-// Return # of bytes till EOF
-int FILEFile::BytesAvailable()
-{
- SInt64 pos = LTell();
- SInt64 endPos = LGetLength();
-
- // Return -1 for major error
- if ((pos==-1) || (endPos==-1))
- {
- ErrorCode = SFerror();
- return 0;
- }
- else
- ErrorCode = 0;
-
- return int (endPos-(int)pos);
-}
-
-// Flush file contents
-bool FILEFile::Flush()
-{
- return !fflush(fs);
-}
-
-int FILEFile::Seek(int offset, int origin)
-{
- int newOrigin = 0;
- switch(origin)
- {
- case Seek_Set: newOrigin = SEEK_SET; break;
- case Seek_Cur: newOrigin = SEEK_CUR; break;
- case Seek_End: newOrigin = SEEK_END; break;
- }
-
- if (newOrigin == SEEK_SET && offset == Tell())
- return Tell();
-
- if (fseek (fs, offset, newOrigin))
- {
-#ifdef OVR_FILE_VERIFY_SEEK_ERRORS
- OVR_ASSERT(0);
-#endif
- return -1;
- }
-
-#ifdef OVR_FILE_VERIFY_SEEK_ERRORS
- // Track file position after seeks for read verification later.
- switch(origin)
- {
- case Seek_Set: TestPos = offset; break;
- case Seek_Cur: TestPos += offset; break;
- case Seek_End: TestPos = FileTestLength + offset; break;
- }
- OVR_ASSERT((int)TestPos == Tell());
-#endif
-
- return (int)Tell();
-}
-
-SInt64 FILEFile::LSeek(SInt64 offset, int origin)
-{
- return Seek((int)offset,origin);
-}
-
-int FILEFile::CopyFromStream(File *pstream, int byteSize)
-{
- UByte buff[0x4000];
- int count = 0;
- int szRequest, szRead, szWritten;
-
- while (byteSize)
- {
- szRequest = (byteSize > int(sizeof(buff))) ? int(sizeof(buff)) : byteSize;
-
- szRead = pstream->Read(buff, szRequest);
- szWritten = 0;
- if (szRead > 0)
- szWritten = Write(buff, szRead);
-
- count += szWritten;
- byteSize -= szWritten;
- if (szWritten < szRequest)
- break;
- }
- return count;
-}
-
-
-bool FILEFile::Close()
-{
-#ifdef OVR_FILE_VERIFY_SEEK_ERRORS
- if (pFileTestBuffer)
- {
- OVR_FREE(pFileTestBuffer);
- pFileTestBuffer = 0;
- FileTestLength = 0;
- }
-#endif
-
- bool closeRet = !fclose(fs);
-
- if (!closeRet)
- {
- ErrorCode = SFerror();
- return 0;
- }
- else
- {
- Opened = 0;
- fs = 0;
- ErrorCode = 0;
- }
-
- // Handle safe truncate
- /*
- if ((OpenFlags & OVR_FO_SAFETRUNC) == OVR_FO_SAFETRUNC)
- {
- // Delete original file (if it existed)
- DWORD oldAttributes = FileUtilWin32::GetFileAttributes(FileName);
- if (oldAttributes!=0xFFFFFFFF)
- if (!FileUtilWin32::DeleteFile(FileName))
- {
- // Try to remove the readonly attribute
- FileUtilWin32::SetFileAttributes(FileName, oldAttributes & (~FILE_ATTRIBUTE_READONLY) );
- // And delete the file again
- if (!FileUtilWin32::DeleteFile(FileName))
- return 0;
- }
-
- // Rename temp file to real filename
- if (!FileUtilWin32::MoveFile(TempName, FileName))
- {
- //ErrorCode = errno;
- return 0;
- }
- }
- */
- return 1;
-}
-
-/*
-bool FILEFile::CloseCancel()
-{
- bool closeRet = (bool)::CloseHandle(fd);
-
- if (!closeRet)
- {
- //ErrorCode = errno;
- return 0;
- }
- else
- {
- Opened = 0;
- fd = INVALID_HANDLE_VALUE;
- ErrorCode = 0;
- }
-
- // Handle safe truncate (delete tmp file, leave original unchanged)
- if ((OpenFlags&OVR_FO_SAFETRUNC) == OVR_FO_SAFETRUNC)
- if (!FileUtilWin32::DeleteFile(TempName))
- {
- //ErrorCode = errno;
- return 0;
- }
- return 1;
-}
-*/
-
-File *FileFILEOpen(const String& path, int flags, int mode)
-{
- return new FILEFile(path, flags, mode);
-}
-
-// Helper function: obtain file information time.
-bool SysFile::GetFileStat(FileStat* pfileStat, const String& path)
-{
-#if defined(OVR_OS_WIN32)
- // 64-bit implementation on Windows.
- struct __stat64 fileStat;
- // Stat returns 0 for success.
- wchar_t *pwpath = (wchar_t*)OVR_ALLOC((UTF8Util::GetLength(path.ToCStr())+1)*sizeof(wchar_t));
- UTF8Util::DecodeString(pwpath, path.ToCStr());
-
- int ret = _wstat64(pwpath, &fileStat);
- OVR_FREE(pwpath);
- if (ret) return false;
-#else
- struct stat fileStat;
- // Stat returns 0 for success.
- if (stat(path, &fileStat) != 0)
- return false;
-#endif
- pfileStat->AccessTime = fileStat.st_atime;
- pfileStat->ModifyTime = fileStat.st_mtime;
- pfileStat->FileSize = fileStat.st_size;
- return true;
-}
-
-} // Scaleform
+/**************************************************************************
+
+Filename : OVR_FileFILE.cpp
+Content : File wrapper class implementation (Win32)
+
+Created : April 5, 1999
+Authors : Michael Antonov
+
+Copyright : Copyright 2012 Oculus VR, Inc. All Rights reserved.
+
+Use of this software is subject to the terms of the Oculus license
+agreement provided at the time of installation or download, or which
+otherwise accompanies this software in either electronic or hard copy form.
+
+**************************************************************************/
+
+#define GFILE_CXX
+
+#include "OVR_Types.h"
+#include "OVR_Log.h"
+
+// Standard C library (Captain Obvious guarantees!)
+#include <stdio.h>
+#ifndef OVR_OS_WINCE
+#include <sys/stat.h>
+#endif
+
+#include "OVR_SysFile.h"
+
+#ifndef OVR_OS_WINCE
+#include <errno.h>
+#endif
+
+namespace OVR {
+
+// ***** File interface
+
+// ***** FILEFile - C streams file
+
+static int SFerror ()
+{
+ if (errno == ENOENT)
+ return FileConstants::Error_FileNotFound;
+ else if (errno == EACCES || errno == EPERM)
+ return FileConstants::Error_Access;
+ else if (errno == ENOSPC)
+ return FileConstants::Error_DiskFull;
+ else
+ return FileConstants::Error_IOError;
+};
+
+#ifdef OVR_OS_WIN32
+#include "windows.h"
+// A simple helper class to disable/enable system error mode, if necessary
+// Disabling happens conditionally only if a drive name is involved
+class SysErrorModeDisabler
+{
+ BOOL Disabled;
+ UINT OldMode;
+public:
+ SysErrorModeDisabler(const char* pfileName)
+ {
+ if (pfileName && (pfileName[0]!=0) && pfileName[1]==':')
+ {
+ Disabled = 1;
+ OldMode = ::SetErrorMode(SEM_FAILCRITICALERRORS);
+ }
+ else
+ Disabled = 0;
+ }
+
+ ~SysErrorModeDisabler()
+ {
+ if (Disabled) ::SetErrorMode(OldMode);
+ }
+};
+#else
+class SysErrorModeDisabler
+{
+public:
+ SysErrorModeDisabler(const char* pfileName) { }
+};
+#endif // OVR_OS_WIN32
+
+
+// This macro enables verification of I/O results after seeks against a pre-loaded
+// full file buffer copy. This is generally not necessary, but can been used to debug
+// memory corruptions; we've seen this fail due to EAX2/DirectSound corrupting memory
+// under FMOD with XP64 (32-bit) and Realtek HA Audio driver.
+//#define GFILE_VERIFY_SEEK_ERRORS
+
+
+// This is the simplest possible file implementation, it wraps around the descriptor
+// This file is delegated to by SysFile.
+
+class FILEFile : public File
+{
+protected:
+
+ // Allocated filename
+ String FileName;
+
+ // File handle & open mode
+ bool Opened;
+ FILE* fs;
+ int OpenFlags;
+ // Error code for last request
+ int ErrorCode;
+
+ int LastOp;
+
+#ifdef OVR_FILE_VERIFY_SEEK_ERRORS
+ UByte* pFileTestBuffer;
+ unsigned FileTestLength;
+ unsigned TestPos; // File pointer position during tests.
+#endif
+
+public:
+
+ FILEFile()
+ {
+ Opened = 0; FileName = "";
+
+#ifdef OVR_FILE_VERIFY_SEEK_ERRORS
+ pFileTestBuffer =0;
+ FileTestLength =0;
+ TestPos =0;
+#endif
+ }
+ // Initialize file by opening it
+ FILEFile(const String& fileName, int flags, int Mode);
+ // The 'pfileName' should be encoded as UTF-8 to support international file names.
+ FILEFile(const char* pfileName, int flags, int Mode);
+
+ ~FILEFile()
+ {
+ if (Opened)
+ Close();
+ }
+
+ virtual const char* GetFilePath();
+
+ // ** File Information
+ virtual bool IsValid();
+ virtual bool IsWritable();
+
+ // Return position / file size
+ virtual int Tell();
+ virtual SInt64 LTell();
+ virtual int GetLength();
+ virtual SInt64 LGetLength();
+
+// virtual bool Stat(FileStats *pfs);
+ virtual int GetErrorCode();
+
+ // ** Stream implementation & I/O
+ virtual int Write(const UByte *pbuffer, int numBytes);
+ virtual int Read(UByte *pbuffer, int numBytes);
+ virtual int SkipBytes(int numBytes);
+ virtual int BytesAvailable();
+ virtual bool Flush();
+ virtual int Seek(int offset, int origin);
+ virtual SInt64 LSeek(SInt64 offset, int origin);
+
+ virtual int CopyFromStream(File *pStream, int byteSize);
+ virtual bool Close();
+private:
+ void init();
+};
+
+
+// Initialize file by opening it
+FILEFile::FILEFile(const String& fileName, int flags, int mode)
+ : FileName(fileName), OpenFlags(flags)
+{
+ OVR_UNUSED(mode);
+ init();
+}
+
+// The 'pfileName' should be encoded as UTF-8 to support international file names.
+FILEFile::FILEFile(const char* pfileName, int flags, int mode)
+ : FileName(pfileName), OpenFlags(flags)
+{
+ OVR_UNUSED(mode);
+ init();
+}
+
+void FILEFile::init()
+{
+ // Open mode for file's open
+ const char *omode = "rb";
+
+ if (OpenFlags & Open_Truncate)
+ {
+ if (OpenFlags & Open_Read)
+ omode = "w+b";
+ else
+ omode = "wb";
+ }
+ else if (OpenFlags & Open_Create)
+ {
+ if (OpenFlags & Open_Read)
+ omode = "a+b";
+ else
+ omode = "ab";
+ }
+ else if (OpenFlags & Open_Write)
+ omode = "r+b";
+
+#ifdef OVR_OS_WIN32
+ SysErrorModeDisabler disabler(FileName.ToCStr());
+#endif
+
+#if defined(OVR_CC_MSVC) && (OVR_CC_MSVC >= 1400)
+ wchar_t womode[16];
+ wchar_t *pwFileName = (wchar_t*)OVR_ALLOC((UTF8Util::GetLength(FileName.ToCStr())+1) * sizeof(wchar_t));
+ UTF8Util::DecodeString(pwFileName, FileName.ToCStr());
+ OVR_ASSERT(strlen(omode) < sizeof(womode)/sizeof(womode[0]));
+ UTF8Util::DecodeString(womode, omode);
+ _wfopen_s(&fs, pwFileName, womode);
+ OVR_FREE(pwFileName);
+#else
+ fs = fopen(FileName.ToCStr(), omode);
+#endif
+ if (fs)
+ rewind (fs);
+ Opened = (fs != NULL);
+ // Set error code
+ if (!Opened)
+ ErrorCode = SFerror();
+ else
+ {
+ // If we are testing file seek correctness, pre-load the entire file so
+ // that we can do comparison tests later.
+#ifdef OVR_FILE_VERIFY_SEEK_ERRORS
+ TestPos = 0;
+ fseek(fs, 0, SEEK_END);
+ FileTestLength = ftell(fs);
+ fseek(fs, 0, SEEK_SET);
+ pFileTestBuffer = (UByte*)OVR_ALLOC(FileTestLength);
+ if (pFileTestBuffer)
+ {
+ OVR_ASSERT(FileTestLength == (unsigned)Read(pFileTestBuffer, FileTestLength));
+ Seek(0, Seek_Set);
+ }
+#endif
+
+ ErrorCode = 0;
+ }
+ LastOp = 0;
+}
+
+
+const char* FILEFile::GetFilePath()
+{
+ return FileName.ToCStr();
+}
+
+
+// ** File Information
+bool FILEFile::IsValid()
+{
+ return Opened;
+}
+bool FILEFile::IsWritable()
+{
+ return IsValid() && (OpenFlags&Open_Write);
+}
+/*
+bool FILEFile::IsRecoverable()
+{
+ return IsValid() && ((OpenFlags&OVR_FO_SAFETRUNC) == OVR_FO_SAFETRUNC);
+}
+*/
+
+// Return position / file size
+int FILEFile::Tell()
+{
+ int pos = (int)ftell (fs);
+ if (pos < 0)
+ ErrorCode = SFerror();
+ return pos;
+}
+
+SInt64 FILEFile::LTell()
+{
+ SInt64 pos = ftell(fs);
+ if (pos < 0)
+ ErrorCode = SFerror();
+ return pos;
+}
+
+int FILEFile::GetLength()
+{
+ int pos = Tell();
+ if (pos >= 0)
+ {
+ Seek (0, Seek_End);
+ int size = Tell();
+ Seek (pos, Seek_Set);
+ return size;
+ }
+ return -1;
+}
+SInt64 FILEFile::LGetLength()
+{
+ SInt64 pos = LTell();
+ if (pos >= 0)
+ {
+ LSeek (0, Seek_End);
+ SInt64 size = LTell();
+ LSeek (pos, Seek_Set);
+ return size;
+ }
+ return -1;
+}
+
+int FILEFile::GetErrorCode()
+{
+ return ErrorCode;
+}
+
+// ** Stream implementation & I/O
+int FILEFile::Write(const UByte *pbuffer, int numBytes)
+{
+ if (LastOp && LastOp != Open_Write)
+ fflush(fs);
+ LastOp = Open_Write;
+ int written = (int) fwrite(pbuffer, 1, numBytes, fs);
+ if (written < numBytes)
+ ErrorCode = SFerror();
+
+#ifdef OVR_FILE_VERIFY_SEEK_ERRORS
+ if (written > 0)
+ TestPos += written;
+#endif
+
+ return written;
+}
+
+int FILEFile::Read(UByte *pbuffer, int numBytes)
+{
+ if (LastOp && LastOp != Open_Read)
+ fflush(fs);
+ LastOp = Open_Read;
+ int read = (int) fread(pbuffer, 1, numBytes, fs);
+ if (read < numBytes)
+ ErrorCode = SFerror();
+
+#ifdef OVR_FILE_VERIFY_SEEK_ERRORS
+ if (read > 0)
+ {
+ // Read-in data must match our pre-loaded buffer data!
+ UByte* pcompareBuffer = pFileTestBuffer + TestPos;
+ for (int i=0; i< read; i++)
+ {
+ OVR_ASSERT(pcompareBuffer[i] == pbuffer[i]);
+ }
+
+ //OVR_ASSERT(!memcmp(pFileTestBuffer + TestPos, pbuffer, read));
+ TestPos += read;
+ OVR_ASSERT(ftell(fs) == (int)TestPos);
+ }
+#endif
+
+ return read;
+}
+
+// Seeks ahead to skip bytes
+int FILEFile::SkipBytes(int numBytes)
+{
+ SInt64 pos = LTell();
+ SInt64 newPos = LSeek(numBytes, Seek_Cur);
+
+ // Return -1 for major error
+ if ((pos==-1) || (newPos==-1))
+ {
+ return -1;
+ }
+ //ErrorCode = ((NewPos-Pos)<numBytes) ? errno : 0;
+
+ return int (newPos-(int)pos);
+}
+
+// Return # of bytes till EOF
+int FILEFile::BytesAvailable()
+{
+ SInt64 pos = LTell();
+ SInt64 endPos = LGetLength();
+
+ // Return -1 for major error
+ if ((pos==-1) || (endPos==-1))
+ {
+ ErrorCode = SFerror();
+ return 0;
+ }
+ else
+ ErrorCode = 0;
+
+ return int (endPos-(int)pos);
+}
+
+// Flush file contents
+bool FILEFile::Flush()
+{
+ return !fflush(fs);
+}
+
+int FILEFile::Seek(int offset, int origin)
+{
+ int newOrigin = 0;
+ switch(origin)
+ {
+ case Seek_Set: newOrigin = SEEK_SET; break;
+ case Seek_Cur: newOrigin = SEEK_CUR; break;
+ case Seek_End: newOrigin = SEEK_END; break;
+ }
+
+ if (newOrigin == SEEK_SET && offset == Tell())
+ return Tell();
+
+ if (fseek (fs, offset, newOrigin))
+ {
+#ifdef OVR_FILE_VERIFY_SEEK_ERRORS
+ OVR_ASSERT(0);
+#endif
+ return -1;
+ }
+
+#ifdef OVR_FILE_VERIFY_SEEK_ERRORS
+ // Track file position after seeks for read verification later.
+ switch(origin)
+ {
+ case Seek_Set: TestPos = offset; break;
+ case Seek_Cur: TestPos += offset; break;
+ case Seek_End: TestPos = FileTestLength + offset; break;
+ }
+ OVR_ASSERT((int)TestPos == Tell());
+#endif
+
+ return (int)Tell();
+}
+
+SInt64 FILEFile::LSeek(SInt64 offset, int origin)
+{
+ return Seek((int)offset,origin);
+}
+
+int FILEFile::CopyFromStream(File *pstream, int byteSize)
+{
+ UByte buff[0x4000];
+ int count = 0;
+ int szRequest, szRead, szWritten;
+
+ while (byteSize)
+ {
+ szRequest = (byteSize > int(sizeof(buff))) ? int(sizeof(buff)) : byteSize;
+
+ szRead = pstream->Read(buff, szRequest);
+ szWritten = 0;
+ if (szRead > 0)
+ szWritten = Write(buff, szRead);
+
+ count += szWritten;
+ byteSize -= szWritten;
+ if (szWritten < szRequest)
+ break;
+ }
+ return count;
+}
+
+
+bool FILEFile::Close()
+{
+#ifdef OVR_FILE_VERIFY_SEEK_ERRORS
+ if (pFileTestBuffer)
+ {
+ OVR_FREE(pFileTestBuffer);
+ pFileTestBuffer = 0;
+ FileTestLength = 0;
+ }
+#endif
+
+ bool closeRet = !fclose(fs);
+
+ if (!closeRet)
+ {
+ ErrorCode = SFerror();
+ return 0;
+ }
+ else
+ {
+ Opened = 0;
+ fs = 0;
+ ErrorCode = 0;
+ }
+
+ // Handle safe truncate
+ /*
+ if ((OpenFlags & OVR_FO_SAFETRUNC) == OVR_FO_SAFETRUNC)
+ {
+ // Delete original file (if it existed)
+ DWORD oldAttributes = FileUtilWin32::GetFileAttributes(FileName);
+ if (oldAttributes!=0xFFFFFFFF)
+ if (!FileUtilWin32::DeleteFile(FileName))
+ {
+ // Try to remove the readonly attribute
+ FileUtilWin32::SetFileAttributes(FileName, oldAttributes & (~FILE_ATTRIBUTE_READONLY) );
+ // And delete the file again
+ if (!FileUtilWin32::DeleteFile(FileName))
+ return 0;
+ }
+
+ // Rename temp file to real filename
+ if (!FileUtilWin32::MoveFile(TempName, FileName))
+ {
+ //ErrorCode = errno;
+ return 0;
+ }
+ }
+ */
+ return 1;
+}
+
+/*
+bool FILEFile::CloseCancel()
+{
+ bool closeRet = (bool)::CloseHandle(fd);
+
+ if (!closeRet)
+ {
+ //ErrorCode = errno;
+ return 0;
+ }
+ else
+ {
+ Opened = 0;
+ fd = INVALID_HANDLE_VALUE;
+ ErrorCode = 0;
+ }
+
+ // Handle safe truncate (delete tmp file, leave original unchanged)
+ if ((OpenFlags&OVR_FO_SAFETRUNC) == OVR_FO_SAFETRUNC)
+ if (!FileUtilWin32::DeleteFile(TempName))
+ {
+ //ErrorCode = errno;
+ return 0;
+ }
+ return 1;
+}
+*/
+
+File *FileFILEOpen(const String& path, int flags, int mode)
+{
+ return new FILEFile(path, flags, mode);
+}
+
+// Helper function: obtain file information time.
+bool SysFile::GetFileStat(FileStat* pfileStat, const String& path)
+{
+#if defined(OVR_OS_WIN32)
+ // 64-bit implementation on Windows.
+ struct __stat64 fileStat;
+ // Stat returns 0 for success.
+ wchar_t *pwpath = (wchar_t*)OVR_ALLOC((UTF8Util::GetLength(path.ToCStr())+1)*sizeof(wchar_t));
+ UTF8Util::DecodeString(pwpath, path.ToCStr());
+
+ int ret = _wstat64(pwpath, &fileStat);
+ OVR_FREE(pwpath);
+ if (ret) return false;
+#else
+ struct stat fileStat;
+ // Stat returns 0 for success.
+ if (stat(path, &fileStat) != 0)
+ return false;
+#endif
+ pfileStat->AccessTime = fileStat.st_atime;
+ pfileStat->ModifyTime = fileStat.st_mtime;
+ pfileStat->FileSize = fileStat.st_size;
+ return true;
+}
+
+} // Scaleform
diff --git a/LibOVR/Src/Kernel/OVR_Hash.h b/LibOVR/Src/Kernel/OVR_Hash.h
index 6667ac2..5fcd6a8 100644
--- a/LibOVR/Src/Kernel/OVR_Hash.h
+++ b/LibOVR/Src/Kernel/OVR_Hash.h
@@ -1,1291 +1,1291 @@
-/************************************************************************************
-
-PublicHeader: None
-Filename : OVR_Hash.h
-Content : Template hash-table/set implementation
-Created : September 19, 2012
-Notes :
-
-Copyright : Copyright 2012 Oculus VR, Inc. All Rights reserved.
-
-Use of this software is subject to the terms of the Oculus license
-agreement provided at the time of installation or download, or which
-otherwise accompanies this software in either electronic or hard copy form.
-
-************************************************************************************/
-
-#ifndef OVR_Hash_h
-#define OVR_Hash_h
-
-#include "OVR_ContainerAllocator.h"
-#include "OVR_Alg.h"
-
-// 'new' operator is redefined/used in this file.
-#undef new
-
-namespace OVR {
-
-//-----------------------------------------------------------------------------------
-// ***** Hash Table Implementation
-
-// HastSet and Hash.
-//
-// Hash table, linear probing, internal chaining. One interesting/nice thing
-// about this implementation is that the table itself is a flat chunk of memory
-// containing no pointers, only relative indices. If the key and value types
-// of the Hash contain no pointers, then the Hash can be serialized using raw IO.
-//
-// Never shrinks, unless you explicitly Clear() it. Expands on
-// demand, though. For best results, if you know roughly how big your
-// table will be, default it to that size when you create it.
-//
-// Key usability feature:
-//
-// 1. Allows node hash values to either be cached or not.
-//
-// 2. Allows for alternative keys with methods such as GetAlt(). Handy
-// if you need to search nodes by their components; no need to create
-// temporary nodes.
-//
-
-
-// *** Hash functors:
-//
-// IdentityHash - use when the key is already a good hash
-// HFixedSizeHash - general hash based on object's in-memory representation.
-
-
-// Hash is just the input value; can use this for integer-indexed hash tables.
-template<class C>
-class IdentityHash
-{
-public:
- UPInt operator()(const C& data) const
- { return (UPInt) data; }
-};
-
-// Computes a hash of an object's representation.
-template<class C>
-class FixedSizeHash
-{
-public:
- // Alternative: "sdbm" hash function, suggested at same web page
- // above, http::/www.cs.yorku.ca/~oz/hash.html
- // This is somewhat slower then Bernstein, but it works way better than the above
- // hash function for hashing large numbers of 32-bit ints.
- static OVR_FORCE_INLINE UPInt SDBM_Hash(const void* data_in, UPInt size, UPInt seed = 5381)
- {
- const UByte* data = (const UByte*) data_in;
- UPInt h = seed;
- while (size > 0)
- {
- size--;
- h = (h << 16) + (h << 6) - h + (UPInt)data[size];
- }
- return h;
- }
-
- UPInt operator()(const C& data) const
- {
- unsigned char* p = (unsigned char*) &data;
- int size = sizeof(C);
-
- return SDBM_Hash(p, size);
- }
-};
-
-
-
-// *** HashsetEntry Entry types.
-
-// Compact hash table Entry type that re-computes hash keys during hash traversal.
-// Good to use if the hash function is cheap or the hash value is already cached in C.
-template<class C, class HashF>
-class HashsetEntry
-{
-public:
- // Internal chaining for collisions.
- SPInt NextInChain;
- C Value;
-
- HashsetEntry()
- : NextInChain(-2) { }
- HashsetEntry(const HashsetEntry& e)
- : NextInChain(e.NextInChain), Value(e.Value) { }
- HashsetEntry(const C& key, SPInt next)
- : NextInChain(next), Value(key) { }
-
- bool IsEmpty() const { return NextInChain == -2; }
- bool IsEndOfChain() const { return NextInChain == -1; }
-
- // Cached hash value access - can be optimized bu storing hash locally.
- // Mask value only needs to be used if SetCachedHash is not implemented.
- UPInt GetCachedHash(UPInt maskValue) const { return HashF()(Value) & maskValue; }
- void SetCachedHash(UPInt) {}
-
- void Clear()
- {
- Value.~C(); // placement delete
- NextInChain = -2;
- }
- // Free is only used from dtor of hash; Clear is used during regular operations:
- // assignment, hash reallocations, value reassignments, so on.
- void Free() { Clear(); }
-};
-
-// Hash table Entry type that caches the Entry hash value for nodes, so that it
-// does not need to be re-computed during access.
-template<class C, class HashF>
-class HashsetCachedEntry
-{
-public:
- // Internal chaining for collisions.
- SPInt NextInChain;
- UPInt HashValue;
- C Value;
-
- HashsetCachedEntry()
- : NextInChain(-2) { }
- HashsetCachedEntry(const HashsetCachedEntry& e)
- : NextInChain(e.NextInChain), HashValue(e.HashValue), Value(e.Value) { }
- HashsetCachedEntry(const C& key, SPInt next)
- : NextInChain(next), Value(key) { }
-
- bool IsEmpty() const { return NextInChain == -2; }
- bool IsEndOfChain() const { return NextInChain == -1; }
-
- // Cached hash value access - can be optimized bu storing hash locally.
- // Mask value only needs to be used if SetCachedHash is not implemented.
- UPInt GetCachedHash(UPInt maskValue) const { OVR_UNUSED(maskValue); return HashValue; }
- void SetCachedHash(UPInt hashValue) { HashValue = hashValue; }
-
- void Clear()
- {
- Value.~C();
- NextInChain = -2;
- }
- // Free is only used from dtor of hash; Clear is used during regular operations:
- // assignment, hash reallocations, value reassignments, so on.
- void Free() { Clear(); }
-};
-
-
-//-----------------------------------------------------------------------------------
-// *** HashSet implementation - relies on either cached or regular entries.
-//
-// Use: Entry = HashsetCachedEntry<C, HashF> if hashes are expensive to
-// compute and thus need caching in entries.
-// Entry = HashsetEntry<C, HashF> if hashes are already externally cached.
-//
-template<class C, class HashF = FixedSizeHash<C>,
- class AltHashF = HashF,
- class Allocator = ContainerAllocator<C>,
- class Entry = HashsetCachedEntry<C, HashF> >
-class HashSetBase
-{
- enum { HashMinSize = 8 };
-
-public:
- OVR_MEMORY_REDEFINE_NEW(HashSetBase)
-
- typedef HashSetBase<C, HashF, AltHashF, Allocator, Entry> SelfType;
-
- HashSetBase() : pTable(NULL) { }
- HashSetBase(int sizeHint) : pTable(NULL) { SetCapacity(this, sizeHint); }
- HashSetBase(const SelfType& src) : pTable(NULL) { Assign(this, src); }
-
- ~HashSetBase()
- {
- if (pTable)
- {
- // Delete the entries.
- for (UPInt i = 0, n = pTable->SizeMask; i <= n; i++)
- {
- Entry* e = &E(i);
- if (!e->IsEmpty())
- e->Free();
- }
-
- Allocator::Free(pTable);
- pTable = NULL;
- }
- }
-
-
- void Assign(const SelfType& src)
- {
- Clear();
- if (src.IsEmpty() == false)
- {
- SetCapacity(src.GetSize());
-
- for (ConstIterator it = src.Begin(); it != src.End(); ++it)
- {
- Add(*it);
- }
- }
- }
-
-
- // Remove all entries from the HashSet table.
- void Clear()
- {
- if (pTable)
- {
- // Delete the entries.
- for (UPInt i = 0, n = pTable->SizeMask; i <= n; i++)
- {
- Entry* e = &E(i);
- if (!e->IsEmpty())
- e->Clear();
- }
-
- Allocator::Free(pTable);
- pTable = NULL;
- }
- }
-
- // Returns true if the HashSet is empty.
- bool IsEmpty() const
- {
- return pTable == NULL || pTable->EntryCount == 0;
- }
-
-
- // Set a new or existing value under the key, to the value.
- // Pass a different class of 'key' so that assignment reference object
- // can be passed instead of the actual object.
- template<class CRef>
- void Set(const CRef& key)
- {
- UPInt hashValue = HashF()(key);
- SPInt index = (SPInt)-1;
-
- if (pTable != NULL)
- index = findIndexCore(key, hashValue & pTable->SizeMask);
-
- if (index >= 0)
- {
- E(index).Value = key;
- }
- else
- {
- // Entry under key doesn't exist.
- add(key, hashValue);
- }
- }
-
- template<class CRef>
- inline void Add(const CRef& key)
- {
- UPInt hashValue = HashF()(key);
- add(key, hashValue);
- }
-
- // Remove by alternative key.
- template<class K>
- void RemoveAlt(const K& key)
- {
- if (pTable == NULL)
- return;
-
- UPInt hashValue = AltHashF()(key);
- SPInt index = hashValue & pTable->SizeMask;
-
- Entry* e = &E(index);
-
- // If empty node or occupied by collider, we have nothing to remove.
- if (e->IsEmpty() || (e->GetCachedHash(pTable->SizeMask) != (UPInt)index))
- return;
-
- // Save index
- SPInt naturalIndex = index;
- SPInt prevIndex = -1;
-
- while ((e->GetCachedHash(pTable->SizeMask) != (UPInt)naturalIndex) || !(e->Value == key))
- {
- // Keep looking through the chain.
- prevIndex = index;
- index = e->NextInChain;
- if (index == -1)
- return; // End of chain, item not found
- e = &E(index);
- }
-
- // Found it - our item is at index
- if (naturalIndex == index)
- {
- // If we have a follower, move it to us
- if (!e->IsEndOfChain())
- {
- Entry* enext = &E(e->NextInChain);
- e->Clear();
- new (e) Entry(*enext);
- // Point us to the follower's cell that will be cleared
- e = enext;
- }
- }
- else
- {
- // We are not at natural index, so deal with the prev items next index
- E(prevIndex).NextInChain = e->NextInChain;
- }
-
- // Clear us, of the follower cell that was moved.
- e->Clear();
- pTable->EntryCount --;
- // Should we check the size to condense hash? ...
- }
-
- // Remove by main key.
- template<class CRef>
- void Remove(const CRef& key)
- {
- RemoveAlt(key);
- }
-
- // Retrieve the pointer to a value under the given key.
- // - If there's no value under the key, then return NULL.
- // - If there is a value, return the pointer.
- template<class K>
- C* Get(const K& key)
- {
- SPInt index = findIndex(key);
- if (index >= 0)
- return &E(index).Value;
- return 0;
- }
-
- template<class K>
- const C* Get(const K& key) const
- {
- SPInt index = findIndex(key);
- if (index >= 0)
- return &E(index).Value;
- return 0;
- }
-
- // Alternative key versions of Get. Used by Hash.
- template<class K>
- const C* GetAlt(const K& key) const
- {
- SPInt index = findIndexAlt(key);
- if (index >= 0)
- return &E(index).Value;
- return 0;
- }
-
- template<class K>
- C* GetAlt(const K& key)
- {
- SPInt index = findIndexAlt(key);
- if (index >= 0)
- return &E(index).Value;
- return 0;
- }
-
- template<class K>
- bool GetAlt(const K& key, C* pval) const
- {
- SPInt index = findIndexAlt(key);
- if (index >= 0)
- {
- if (pval)
- *pval = E(index).Value;
- return true;
- }
- return false;
- }
-
-
- UPInt GetSize() const
- {
- return pTable == NULL ? 0 : (UPInt)pTable->EntryCount;
- }
-
-
- // Resize the HashSet table to fit one more Entry. Often this
- // doesn't involve any action.
- void CheckExpand()
- {
- if (pTable == NULL)
- {
- // Initial creation of table. Make a minimum-sized table.
- setRawCapacity(HashMinSize);
- }
- else if (pTable->EntryCount * 5 > (pTable->SizeMask + 1) * 4)
- {
- // pTable is more than 5/4 ths full. Expand.
- setRawCapacity((pTable->SizeMask + 1) * 2);
- }
- }
-
- // Hint the bucket count to >= n.
- void Resize(UPInt n)
- {
- // Not really sure what this means in relation to
- // STLport's hash_map... they say they "increase the
- // bucket count to at least n" -- but does that mean
- // their real capacity after Resize(n) is more like
- // n*2 (since they do linked-list chaining within
- // buckets?).
- SetCapacity(n);
- }
-
- // Size the HashSet so that it can comfortably contain the given
- // number of elements. If the HashSet already contains more
- // elements than newSize, then this may be a no-op.
- void SetCapacity(UPInt newSize)
- {
- UPInt newRawSize = (newSize * 5) / 4;
- if (newRawSize <= GetSize())
- return;
- setRawCapacity(newRawSize);
- }
-
- // Disable inappropriate 'operator ->' warning on MSVC6.
-#ifdef OVR_CC_MSVC
-#if (OVR_CC_MSVC < 1300)
-# pragma warning(disable : 4284)
-#endif
-#endif
-
- // Iterator API, like STL.
- struct ConstIterator
- {
- const C& operator * () const
- {
- OVR_ASSERT(Index >= 0 && Index <= (SPInt)pHash->pTable->SizeMask);
- return pHash->E(Index).Value;
- }
-
- const C* operator -> () const
- {
- OVR_ASSERT(Index >= 0 && Index <= (SPInt)pHash->pTable->SizeMask);
- return &pHash->E(Index).Value;
- }
-
- void operator ++ ()
- {
- // Find next non-empty Entry.
- if (Index <= (SPInt)pHash->pTable->SizeMask)
- {
- Index++;
- while ((UPInt)Index <= pHash->pTable->SizeMask &&
- pHash->E(Index).IsEmpty())
- {
- Index++;
- }
- }
- }
-
- bool operator == (const ConstIterator& it) const
- {
- if (IsEnd() && it.IsEnd())
- {
- return true;
- }
- else
- {
- return (pHash == it.pHash) && (Index == it.Index);
- }
- }
-
- bool operator != (const ConstIterator& it) const
- {
- return ! (*this == it);
- }
-
-
- bool IsEnd() const
- {
- return (pHash == NULL) ||
- (pHash->pTable == NULL) ||
- (Index > (SPInt)pHash->pTable->SizeMask);
- }
-
- ConstIterator()
- : pHash(NULL), Index(0)
- { }
-
- public:
- // Constructor was intentionally made public to allow create
- // iterator with arbitrary index.
- ConstIterator(const SelfType* h, SPInt index)
- : pHash(h), Index(index)
- { }
-
- const SelfType* GetContainer() const
- {
- return pHash;
- }
- SPInt GetIndex() const
- {
- return Index;
- }
-
- protected:
- friend class HashSetBase<C, HashF, AltHashF, Allocator, Entry>;
-
- const SelfType* pHash;
- SPInt Index;
- };
-
- friend struct ConstIterator;
-
-
- // Non-const Iterator; Get most of it from ConstIterator.
- struct Iterator : public ConstIterator
- {
- // Allow non-const access to entries.
- C& operator*() const
- {
- OVR_ASSERT(ConstIterator::Index >= 0 && ConstIterator::Index <= (SPInt)ConstIterator::pHash->pTable->SizeMask);
- return const_cast<SelfType*>(ConstIterator::pHash)->E(ConstIterator::Index).Value;
- }
-
- C* operator->() const
- {
- return &(operator*());
- }
-
- Iterator()
- : ConstIterator(NULL, 0)
- { }
-
- // Removes current element from Hash
- void Remove()
- {
- RemoveAlt(operator*());
- }
-
- template <class K>
- void RemoveAlt(const K& key)
- {
- SelfType* phash = const_cast<SelfType*>(ConstIterator::pHash);
- //Entry* ee = &phash->E(ConstIterator::Index);
- //const C& key = ee->Value;
-
- UPInt hashValue = AltHashF()(key);
- SPInt index = hashValue & phash->pTable->SizeMask;
-
- Entry* e = &phash->E(index);
-
- // If empty node or occupied by collider, we have nothing to remove.
- if (e->IsEmpty() || (e->GetCachedHash(phash->pTable->SizeMask) != (UPInt)index))
- return;
-
- // Save index
- SPInt naturalIndex = index;
- SPInt prevIndex = -1;
-
- while ((e->GetCachedHash(phash->pTable->SizeMask) != (UPInt)naturalIndex) || !(e->Value == key))
- {
- // Keep looking through the chain.
- prevIndex = index;
- index = e->NextInChain;
- if (index == -1)
- return; // End of chain, item not found
- e = &phash->E(index);
- }
-
- if (index == (SPInt)ConstIterator::Index)
- {
- // Found it - our item is at index
- if (naturalIndex == index)
- {
- // If we have a follower, move it to us
- if (!e->IsEndOfChain())
- {
- Entry* enext = &phash->E(e->NextInChain);
- e->Clear();
- new (e) Entry(*enext);
- // Point us to the follower's cell that will be cleared
- e = enext;
- --ConstIterator::Index;
- }
- }
- else
- {
- // We are not at natural index, so deal with the prev items next index
- phash->E(prevIndex).NextInChain = e->NextInChain;
- }
-
- // Clear us, of the follower cell that was moved.
- e->Clear();
- phash->pTable->EntryCount --;
- }
- else
- OVR_ASSERT(0); //?
- }
-
- private:
- friend class HashSetBase<C, HashF, AltHashF, Allocator, Entry>;
-
- Iterator(SelfType* h, SPInt i0)
- : ConstIterator(h, i0)
- { }
- };
-
- friend struct Iterator;
-
- Iterator Begin()
- {
- if (pTable == 0)
- return Iterator(NULL, 0);
-
- // Scan till we hit the First valid Entry.
- UPInt i0 = 0;
- while (i0 <= pTable->SizeMask && E(i0).IsEmpty())
- {
- i0++;
- }
- return Iterator(this, i0);
- }
- Iterator End() { return Iterator(NULL, 0); }
-
- ConstIterator Begin() const { return const_cast<SelfType*>(this)->Begin(); }
- ConstIterator End() const { return const_cast<SelfType*>(this)->End(); }
-
- template<class K>
- Iterator Find(const K& key)
- {
- SPInt index = findIndex(key);
- if (index >= 0)
- return Iterator(this, index);
- return Iterator(NULL, 0);
- }
-
- template<class K>
- Iterator FindAlt(const K& key)
- {
- SPInt index = findIndexAlt(key);
- if (index >= 0)
- return Iterator(this, index);
- return Iterator(NULL, 0);
- }
-
- template<class K>
- ConstIterator Find(const K& key) const { return const_cast<SelfType*>(this)->Find(key); }
-
- template<class K>
- ConstIterator FindAlt(const K& key) const { return const_cast<SelfType*>(this)->FindAlt(key); }
-
-private:
- // Find the index of the matching Entry. If no match, then return -1.
- template<class K>
- SPInt findIndex(const K& key) const
- {
- if (pTable == NULL)
- return -1;
- UPInt hashValue = HashF()(key) & pTable->SizeMask;
- return findIndexCore(key, hashValue);
- }
-
- template<class K>
- SPInt findIndexAlt(const K& key) const
- {
- if (pTable == NULL)
- return -1;
- UPInt hashValue = AltHashF()(key) & pTable->SizeMask;
- return findIndexCore(key, hashValue);
- }
-
- // Find the index of the matching Entry. If no match, then return -1.
- template<class K>
- SPInt findIndexCore(const K& key, UPInt hashValue) const
- {
- // Table must exist.
- OVR_ASSERT(pTable != 0);
- // Hash key must be 'and-ed' by the caller.
- OVR_ASSERT((hashValue & ~pTable->SizeMask) == 0);
-
- UPInt index = hashValue;
- const Entry* e = &E(index);
-
- // If empty or occupied by a collider, not found.
- if (e->IsEmpty() || (e->GetCachedHash(pTable->SizeMask) != index))
- return -1;
-
- while(1)
- {
- OVR_ASSERT(e->GetCachedHash(pTable->SizeMask) == hashValue);
-
- if (e->GetCachedHash(pTable->SizeMask) == hashValue && e->Value == key)
- {
- // Found it.
- return index;
- }
- // Values can not be equal at this point.
- // That would mean that the hash key for the same value differs.
- OVR_ASSERT(!(e->Value == key));
-
- // Keep looking through the chain.
- index = e->NextInChain;
- if (index == (UPInt)-1)
- break; // end of chain
-
- e = &E(index);
- OVR_ASSERT(!e->IsEmpty());
- }
- return -1;
- }
-
-
- // Add a new value to the HashSet table, under the specified key.
- template<class CRef>
- void add(const CRef& key, UPInt hashValue)
- {
- CheckExpand();
- hashValue &= pTable->SizeMask;
-
- pTable->EntryCount++;
-
- SPInt index = hashValue;
- Entry* naturalEntry = &(E(index));
-
- if (naturalEntry->IsEmpty())
- {
- // Put the new Entry in.
- new (naturalEntry) Entry(key, -1);
- }
- else
- {
- // Find a blank spot.
- SPInt blankIndex = index;
- do {
- blankIndex = (blankIndex + 1) & pTable->SizeMask;
- } while(!E(blankIndex).IsEmpty());
-
- Entry* blankEntry = &E(blankIndex);
-
- if (naturalEntry->GetCachedHash(pTable->SizeMask) == (UPInt)index)
- {
- // Collision. Link into this chain.
-
- // Move existing list head.
- new (blankEntry) Entry(*naturalEntry); // placement new, copy ctor
-
- // Put the new info in the natural Entry.
- naturalEntry->Value = key;
- naturalEntry->NextInChain = blankIndex;
- }
- else
- {
- // Existing Entry does not naturally
- // belong in this slot. Existing
- // Entry must be moved.
-
- // Find natural location of collided element (i.e. root of chain)
- SPInt collidedIndex = naturalEntry->GetCachedHash(pTable->SizeMask);
- OVR_ASSERT(collidedIndex >= 0 && collidedIndex <= (SPInt)pTable->SizeMask);
- for (;;)
- {
- Entry* e = &E(collidedIndex);
- if (e->NextInChain == index)
- {
- // Here's where we need to splice.
- new (blankEntry) Entry(*naturalEntry);
- e->NextInChain = blankIndex;
- break;
- }
- collidedIndex = e->NextInChain;
- OVR_ASSERT(collidedIndex >= 0 && collidedIndex <= (SPInt)pTable->SizeMask);
- }
-
- // Put the new data in the natural Entry.
- naturalEntry->Value = key;
- naturalEntry->NextInChain = -1;
- }
- }
-
- // Record hash value: has effect only if cached node is used.
- naturalEntry->SetCachedHash(hashValue);
- }
-
- // Index access helpers.
- Entry& E(UPInt index)
- {
- // Must have pTable and access needs to be within bounds.
- OVR_ASSERT(index <= pTable->SizeMask);
- return *(((Entry*) (pTable + 1)) + index);
- }
- const Entry& E(UPInt index) const
- {
- OVR_ASSERT(index <= pTable->SizeMask);
- return *(((Entry*) (pTable + 1)) + index);
- }
-
-
- // Resize the HashSet table to the given size (Rehash the
- // contents of the current table). The arg is the number of
- // HashSet table entries, not the number of elements we should
- // actually contain (which will be less than this).
- void setRawCapacity(UPInt newSize)
- {
- if (newSize == 0)
- {
- // Special case.
- Clear();
- return;
- }
-
- // Minimum size; don't incur rehashing cost when expanding
- // very small tables. Not that we perform this check before
- // 'log2f' call to avoid fp exception with newSize == 1.
- if (newSize < HashMinSize)
- newSize = HashMinSize;
- else
- {
- // Force newSize to be a power of two.
- int bits = Alg::UpperBit(newSize-1) + 1; // Chop( Log2f((float)(newSize-1)) + 1);
- OVR_ASSERT((UPInt(1) << bits) >= newSize);
- newSize = UPInt(1) << bits;
- }
-
- SelfType newHash;
- newHash.pTable = (TableType*)
- Allocator::Alloc(
- sizeof(TableType) + sizeof(Entry) * newSize);
- // Need to do something on alloc failure!
- OVR_ASSERT(newHash.pTable);
-
- newHash.pTable->EntryCount = 0;
- newHash.pTable->SizeMask = newSize - 1;
- UPInt i, n;
-
- // Mark all entries as empty.
- for (i = 0; i < newSize; i++)
- newHash.E(i).NextInChain = -2;
-
- // Copy stuff to newHash
- if (pTable)
- {
- for (i = 0, n = pTable->SizeMask; i <= n; i++)
- {
- Entry* e = &E(i);
- if (e->IsEmpty() == false)
- {
- // Insert old Entry into new HashSet.
- newHash.Add(e->Value);
- // placement delete of old element
- e->Clear();
- }
- }
-
- // Delete our old data buffer.
- Allocator::Free(pTable);
- }
-
- // Steal newHash's data.
- pTable = newHash.pTable;
- newHash.pTable = NULL;
- }
-
- struct TableType
- {
- UPInt EntryCount;
- UPInt SizeMask;
- // Entry array follows this structure
- // in memory.
- };
- TableType* pTable;
-};
-
-
-
-//-----------------------------------------------------------------------------------
-template<class C, class HashF = FixedSizeHash<C>,
- class AltHashF = HashF,
- class Allocator = ContainerAllocator<C>,
- class Entry = HashsetCachedEntry<C, HashF> >
-class HashSet : public HashSetBase<C, HashF, AltHashF, Allocator, Entry>
-{
-public:
- typedef HashSetBase<C, HashF, AltHashF, Allocator, Entry> BaseType;
- typedef HashSet<C, HashF, AltHashF, Allocator, Entry> SelfType;
-
- HashSet() { }
- HashSet(int sizeHint) : BaseType(sizeHint) { }
- HashSet(const SelfType& src) : BaseType(src) { }
- ~HashSet() { }
-
- void operator = (const SelfType& src) { BaseType::Assign(src); }
-
- // Set a new or existing value under the key, to the value.
- // Pass a different class of 'key' so that assignment reference object
- // can be passed instead of the actual object.
- template<class CRef>
- void Set(const CRef& key)
- {
- BaseType::Set(key);
- }
-
- template<class CRef>
- inline void Add(const CRef& key)
- {
- BaseType::Add(key);
- }
-
- // Hint the bucket count to >= n.
- void Resize(UPInt n)
- {
- BaseType::SetCapacity(n);
- }
-
- // Size the HashSet so that it can comfortably contain the given
- // number of elements. If the HashSet already contains more
- // elements than newSize, then this may be a no-op.
- void SetCapacity(UPInt newSize)
- {
- BaseType::SetCapacity(newSize);
- }
-
-};
-
-// HashSet with uncached hash code; declared for convenience.
-template<class C, class HashF = FixedSizeHash<C>,
- class AltHashF = HashF,
- class Allocator = ContainerAllocator<C> >
-class HashSetUncached : public HashSet<C, HashF, AltHashF, Allocator, HashsetEntry<C, HashF> >
-{
-public:
-
- typedef HashSetUncached<C, HashF, AltHashF, Allocator> SelfType;
- typedef HashSet<C, HashF, AltHashF, Allocator, HashsetEntry<C, HashF> > BaseType;
-
- // Delegated constructors.
- HashSetUncached() { }
- HashSetUncached(int sizeHint) : BaseType(sizeHint) { }
- HashSetUncached(const SelfType& src) : BaseType(src) { }
- ~HashSetUncached() { }
-
- void operator = (const SelfType& src)
- {
- BaseType::operator = (src);
- }
-};
-
-
-//-----------------------------------------------------------------------------------
-// ***** Hash hash table implementation
-
-// Node for Hash - necessary so that Hash can delegate its implementation
-// to HashSet.
-template<class C, class U, class HashF>
-struct HashNode
-{
- typedef HashNode<C, U, HashF> SelfType;
- typedef C FirstType;
- typedef U SecondType;
-
- C First;
- U Second;
-
- // NodeRef is used to allow passing of elements into HashSet
- // without using a temporary object.
- struct NodeRef
- {
- const C* pFirst;
- const U* pSecond;
-
- NodeRef(const C& f, const U& s) : pFirst(&f), pSecond(&s) { }
- NodeRef(const NodeRef& src) : pFirst(src.pFirst), pSecond(src.pSecond) { }
-
- // Enable computation of ghash_node_hashf.
- inline UPInt GetHash() const { return HashF()(*pFirst); }
- // Necessary conversion to allow HashNode::operator == to work.
- operator const C& () const { return *pFirst; }
- };
-
- // Note: No default constructor is necessary.
- HashNode(const HashNode& src) : First(src.First), Second(src.Second) { }
- HashNode(const NodeRef& src) : First(*src.pFirst), Second(*src.pSecond) { }
- void operator = (const NodeRef& src) { First = *src.pFirst; Second = *src.pSecond; }
-
- template<class K>
- bool operator == (const K& src) const { return (First == src); }
-
- template<class K>
- static UPInt CalcHash(const K& data) { return HashF()(data); }
- inline UPInt GetHash() const { return HashF()(First); }
-
- // Hash functors used with this node. A separate functor is used for alternative
- // key lookup so that it does not need to access the '.First' element.
- struct NodeHashF
- {
- template<class K>
- UPInt operator()(const K& data) const { return data.GetHash(); }
- };
- struct NodeAltHashF
- {
- template<class K>
- UPInt operator()(const K& data) const { return HashNode<C,U,HashF>::CalcHash(data); }
- };
-};
-
-
-
-// **** Extra hashset_entry types to allow NodeRef construction.
-
-// The big difference between the below types and the ones used in hash_set is that
-// these allow initializing the node with 'typename C::NodeRef& keyRef', which
-// is critical to avoid temporary node allocation on stack when using placement new.
-
-// Compact hash table Entry type that re-computes hash keys during hash traversal.
-// Good to use if the hash function is cheap or the hash value is already cached in C.
-template<class C, class HashF>
-class HashsetNodeEntry
-{
-public:
- // Internal chaining for collisions.
- SPInt NextInChain;
- C Value;
-
- HashsetNodeEntry()
- : NextInChain(-2) { }
- HashsetNodeEntry(const HashsetNodeEntry& e)
- : NextInChain(e.NextInChain), Value(e.Value) { }
- HashsetNodeEntry(const C& key, SPInt next)
- : NextInChain(next), Value(key) { }
- HashsetNodeEntry(const typename C::NodeRef& keyRef, SPInt next)
- : NextInChain(next), Value(keyRef) { }
-
- bool IsEmpty() const { return NextInChain == -2; }
- bool IsEndOfChain() const { return NextInChain == -1; }
- UPInt GetCachedHash(UPInt maskValue) const { return HashF()(Value) & maskValue; }
- void SetCachedHash(UPInt hashValue) { OVR_UNUSED(hashValue); }
-
- void Clear()
- {
- Value.~C(); // placement delete
- NextInChain = -2;
- }
- // Free is only used from dtor of hash; Clear is used during regular operations:
- // assignment, hash reallocations, value reassignments, so on.
- void Free() { Clear(); }
-};
-
-// Hash table Entry type that caches the Entry hash value for nodes, so that it
-// does not need to be re-computed during access.
-template<class C, class HashF>
-class HashsetCachedNodeEntry
-{
-public:
- // Internal chaining for collisions.
- SPInt NextInChain;
- UPInt HashValue;
- C Value;
-
- HashsetCachedNodeEntry()
- : NextInChain(-2) { }
- HashsetCachedNodeEntry(const HashsetCachedNodeEntry& e)
- : NextInChain(e.NextInChain), HashValue(e.HashValue), Value(e.Value) { }
- HashsetCachedNodeEntry(const C& key, SPInt next)
- : NextInChain(next), Value(key) { }
- HashsetCachedNodeEntry(const typename C::NodeRef& keyRef, SPInt next)
- : NextInChain(next), Value(keyRef) { }
-
- bool IsEmpty() const { return NextInChain == -2; }
- bool IsEndOfChain() const { return NextInChain == -1; }
- UPInt GetCachedHash(UPInt maskValue) const { OVR_UNUSED(maskValue); return HashValue; }
- void SetCachedHash(UPInt hashValue) { HashValue = hashValue; }
-
- void Clear()
- {
- Value.~C();
- NextInChain = -2;
- }
- // Free is only used from dtor of hash; Clear is used during regular operations:
- // assignment, hash reallocations, value reassignments, so on.
- void Free() { Clear(); }
-};
-
-
-//-----------------------------------------------------------------------------------
-template<class C, class U,
- class HashF = FixedSizeHash<C>,
- class Allocator = ContainerAllocator<C>,
- class HashNode = OVR::HashNode<C,U,HashF>,
- class Entry = HashsetCachedNodeEntry<HashNode, typename HashNode::NodeHashF>,
- class Container = HashSet<HashNode, typename HashNode::NodeHashF,
- typename HashNode::NodeAltHashF, Allocator,
- Entry> >
-class Hash
-{
-public:
- OVR_MEMORY_REDEFINE_NEW(Hash)
-
- // Types used for hash_set.
- typedef U ValueType;
- typedef Hash<C, U, HashF, Allocator, HashNode, Entry, Container> SelfType;
-
- // Actual hash table itself, implemented as hash_set.
- Container mHash;
-
-public:
- Hash() { }
- Hash(int sizeHint) : mHash(sizeHint) { }
- Hash(const SelfType& src) : mHash(src.mHash) { }
- ~Hash() { }
-
- void operator = (const SelfType& src) { mHash = src.mHash; }
-
- // Remove all entries from the Hash table.
- inline void Clear() { mHash.Clear(); }
- // Returns true if the Hash is empty.
- inline bool IsEmpty() const { return mHash.IsEmpty(); }
-
- // Access (set).
- inline void Set(const C& key, const U& value)
- {
- typename HashNode::NodeRef e(key, value);
- mHash.Set(e);
- }
- inline void Add(const C& key, const U& value)
- {
- typename HashNode::NodeRef e(key, value);
- mHash.Add(e);
- }
-
- // Removes an element by clearing its Entry.
- inline void Remove(const C& key)
- {
- mHash.RemoveAlt(key);
- }
- template<class K>
- inline void RemoveAlt(const K& key)
- {
- mHash.RemoveAlt(key);
- }
-
- // Retrieve the value under the given key.
- // - If there's no value under the key, then return false and leave *pvalue alone.
- // - If there is a value, return true, and Set *Pvalue to the Entry's value.
- // - If value == NULL, return true or false according to the presence of the key.
- bool Get(const C& key, U* pvalue) const
- {
- const HashNode* p = mHash.GetAlt(key);
- if (p)
- {
- if (pvalue)
- *pvalue = p->Second;
- return true;
- }
- return false;
- }
-
- template<class K>
- bool GetAlt(const K& key, U* pvalue) const
- {
- const HashNode* p = mHash.GetAlt(key);
- if (p)
- {
- if (pvalue)
- *pvalue = p->Second;
- return true;
- }
- return false;
- }
-
- // Retrieve the pointer to a value under the given key.
- // - If there's no value under the key, then return NULL.
- // - If there is a value, return the pointer.
- inline U* Get(const C& key)
- {
- HashNode* p = mHash.GetAlt(key);
- return p ? &p->Second : 0;
- }
- inline const U* Get(const C& key) const
- {
- const HashNode* p = mHash.GetAlt(key);
- return p ? &p->Second : 0;
- }
-
- template<class K>
- inline U* GetAlt(const K& key)
- {
- HashNode* p = mHash.GetAlt(key);
- return p ? &p->Second : 0;
- }
- template<class K>
- inline const U* GetAlt(const K& key) const
- {
- const HashNode* p = mHash.GetAlt(key);
- return p ? &p->Second : 0;
- }
-
- // Sizing methods - delegate to Hash.
- inline UPInt GetSize() const { return mHash.GetSize(); }
- inline void Resize(UPInt n) { mHash.Resize(n); }
- inline void SetCapacity(UPInt newSize) { mHash.SetCapacity(newSize); }
-
- // Iterator API, like STL.
- typedef typename Container::ConstIterator ConstIterator;
- typedef typename Container::Iterator Iterator;
-
- inline Iterator Begin() { return mHash.Begin(); }
- inline Iterator End() { return mHash.End(); }
- inline ConstIterator Begin() const { return mHash.Begin(); }
- inline ConstIterator End() const { return mHash.End(); }
-
- Iterator Find(const C& key) { return mHash.FindAlt(key); }
- ConstIterator Find(const C& key) const { return mHash.FindAlt(key); }
-
- template<class K>
- Iterator FindAlt(const K& key) { return mHash.FindAlt(key); }
- template<class K>
- ConstIterator FindAlt(const K& key) const { return mHash.FindAlt(key); }
-};
-
-
-
-// Hash with uncached hash code; declared for convenience.
-template<class C, class U, class HashF = FixedSizeHash<C>, class Allocator = ContainerAllocator<C> >
-class HashUncached
- : public Hash<C, U, HashF, Allocator, HashNode<C,U,HashF>,
- HashsetNodeEntry<HashNode<C,U,HashF>, typename HashNode<C,U,HashF>::NodeHashF> >
-{
-public:
- typedef HashUncached<C, U, HashF, Allocator> SelfType;
- typedef Hash<C, U, HashF, Allocator, HashNode<C,U,HashF>,
- HashsetNodeEntry<HashNode<C,U,HashF>,
- typename HashNode<C,U,HashF>::NodeHashF> > BaseType;
-
- // Delegated constructors.
- HashUncached() { }
- HashUncached(int sizeHint) : BaseType(sizeHint) { }
- HashUncached(const SelfType& src) : BaseType(src) { }
- ~HashUncached() { }
- void operator = (const SelfType& src) { BaseType::operator = (src); }
-};
-
-
-
-// And identity hash in which keys serve as hash value. Can be uncached,
-// since hash computation is assumed cheap.
-template<class C, class U, class Allocator = ContainerAllocator<C>, class HashF = IdentityHash<C> >
-class HashIdentity
- : public HashUncached<C, U, HashF, Allocator>
-{
-public:
- typedef HashIdentity<C, U, Allocator, HashF> SelfType;
- typedef HashUncached<C, U, HashF, Allocator> BaseType;
-
- // Delegated constructors.
- HashIdentity() { }
- HashIdentity(int sizeHint) : BaseType(sizeHint) { }
- HashIdentity(const SelfType& src) : BaseType(src) { }
- ~HashIdentity() { }
- void operator = (const SelfType& src) { BaseType::operator = (src); }
-};
-
-
-} // OVR
-
-
-#ifdef OVR_DEFINE_NEW
-#define new OVR_DEFINE_NEW
-#endif
-
-#endif
+/************************************************************************************
+
+PublicHeader: None
+Filename : OVR_Hash.h
+Content : Template hash-table/set implementation
+Created : September 19, 2012
+Notes :
+
+Copyright : Copyright 2012 Oculus VR, Inc. All Rights reserved.
+
+Use of this software is subject to the terms of the Oculus license
+agreement provided at the time of installation or download, or which
+otherwise accompanies this software in either electronic or hard copy form.
+
+************************************************************************************/
+
+#ifndef OVR_Hash_h
+#define OVR_Hash_h
+
+#include "OVR_ContainerAllocator.h"
+#include "OVR_Alg.h"
+
+// 'new' operator is redefined/used in this file.
+#undef new
+
+namespace OVR {
+
+//-----------------------------------------------------------------------------------
+// ***** Hash Table Implementation
+
+// HastSet and Hash.
+//
+// Hash table, linear probing, internal chaining. One interesting/nice thing
+// about this implementation is that the table itself is a flat chunk of memory
+// containing no pointers, only relative indices. If the key and value types
+// of the Hash contain no pointers, then the Hash can be serialized using raw IO.
+//
+// Never shrinks, unless you explicitly Clear() it. Expands on
+// demand, though. For best results, if you know roughly how big your
+// table will be, default it to that size when you create it.
+//
+// Key usability feature:
+//
+// 1. Allows node hash values to either be cached or not.
+//
+// 2. Allows for alternative keys with methods such as GetAlt(). Handy
+// if you need to search nodes by their components; no need to create
+// temporary nodes.
+//
+
+
+// *** Hash functors:
+//
+// IdentityHash - use when the key is already a good hash
+// HFixedSizeHash - general hash based on object's in-memory representation.
+
+
+// Hash is just the input value; can use this for integer-indexed hash tables.
+template<class C>
+class IdentityHash
+{
+public:
+ UPInt operator()(const C& data) const
+ { return (UPInt) data; }
+};
+
+// Computes a hash of an object's representation.
+template<class C>
+class FixedSizeHash
+{
+public:
+ // Alternative: "sdbm" hash function, suggested at same web page
+ // above, http::/www.cs.yorku.ca/~oz/hash.html
+ // This is somewhat slower then Bernstein, but it works way better than the above
+ // hash function for hashing large numbers of 32-bit ints.
+ static OVR_FORCE_INLINE UPInt SDBM_Hash(const void* data_in, UPInt size, UPInt seed = 5381)
+ {
+ const UByte* data = (const UByte*) data_in;
+ UPInt h = seed;
+ while (size > 0)
+ {
+ size--;
+ h = (h << 16) + (h << 6) - h + (UPInt)data[size];
+ }
+ return h;
+ }
+
+ UPInt operator()(const C& data) const
+ {
+ unsigned char* p = (unsigned char*) &data;
+ int size = sizeof(C);
+
+ return SDBM_Hash(p, size);
+ }
+};
+
+
+
+// *** HashsetEntry Entry types.
+
+// Compact hash table Entry type that re-computes hash keys during hash traversal.
+// Good to use if the hash function is cheap or the hash value is already cached in C.
+template<class C, class HashF>
+class HashsetEntry
+{
+public:
+ // Internal chaining for collisions.
+ SPInt NextInChain;
+ C Value;
+
+ HashsetEntry()
+ : NextInChain(-2) { }
+ HashsetEntry(const HashsetEntry& e)
+ : NextInChain(e.NextInChain), Value(e.Value) { }
+ HashsetEntry(const C& key, SPInt next)
+ : NextInChain(next), Value(key) { }
+
+ bool IsEmpty() const { return NextInChain == -2; }
+ bool IsEndOfChain() const { return NextInChain == -1; }
+
+ // Cached hash value access - can be optimized bu storing hash locally.
+ // Mask value only needs to be used if SetCachedHash is not implemented.
+ UPInt GetCachedHash(UPInt maskValue) const { return HashF()(Value) & maskValue; }
+ void SetCachedHash(UPInt) {}
+
+ void Clear()
+ {
+ Value.~C(); // placement delete
+ NextInChain = -2;
+ }
+ // Free is only used from dtor of hash; Clear is used during regular operations:
+ // assignment, hash reallocations, value reassignments, so on.
+ void Free() { Clear(); }
+};
+
+// Hash table Entry type that caches the Entry hash value for nodes, so that it
+// does not need to be re-computed during access.
+template<class C, class HashF>
+class HashsetCachedEntry
+{
+public:
+ // Internal chaining for collisions.
+ SPInt NextInChain;
+ UPInt HashValue;
+ C Value;
+
+ HashsetCachedEntry()
+ : NextInChain(-2) { }
+ HashsetCachedEntry(const HashsetCachedEntry& e)
+ : NextInChain(e.NextInChain), HashValue(e.HashValue), Value(e.Value) { }
+ HashsetCachedEntry(const C& key, SPInt next)
+ : NextInChain(next), Value(key) { }
+
+ bool IsEmpty() const { return NextInChain == -2; }
+ bool IsEndOfChain() const { return NextInChain == -1; }
+
+ // Cached hash value access - can be optimized bu storing hash locally.
+ // Mask value only needs to be used if SetCachedHash is not implemented.
+ UPInt GetCachedHash(UPInt maskValue) const { OVR_UNUSED(maskValue); return HashValue; }
+ void SetCachedHash(UPInt hashValue) { HashValue = hashValue; }
+
+ void Clear()
+ {
+ Value.~C();
+ NextInChain = -2;
+ }
+ // Free is only used from dtor of hash; Clear is used during regular operations:
+ // assignment, hash reallocations, value reassignments, so on.
+ void Free() { Clear(); }
+};
+
+
+//-----------------------------------------------------------------------------------
+// *** HashSet implementation - relies on either cached or regular entries.
+//
+// Use: Entry = HashsetCachedEntry<C, HashF> if hashes are expensive to
+// compute and thus need caching in entries.
+// Entry = HashsetEntry<C, HashF> if hashes are already externally cached.
+//
+template<class C, class HashF = FixedSizeHash<C>,
+ class AltHashF = HashF,
+ class Allocator = ContainerAllocator<C>,
+ class Entry = HashsetCachedEntry<C, HashF> >
+class HashSetBase
+{
+ enum { HashMinSize = 8 };
+
+public:
+ OVR_MEMORY_REDEFINE_NEW(HashSetBase)
+
+ typedef HashSetBase<C, HashF, AltHashF, Allocator, Entry> SelfType;
+
+ HashSetBase() : pTable(NULL) { }
+ HashSetBase(int sizeHint) : pTable(NULL) { SetCapacity(this, sizeHint); }
+ HashSetBase(const SelfType& src) : pTable(NULL) { Assign(this, src); }
+
+ ~HashSetBase()
+ {
+ if (pTable)
+ {
+ // Delete the entries.
+ for (UPInt i = 0, n = pTable->SizeMask; i <= n; i++)
+ {
+ Entry* e = &E(i);
+ if (!e->IsEmpty())
+ e->Free();
+ }
+
+ Allocator::Free(pTable);
+ pTable = NULL;
+ }
+ }
+
+
+ void Assign(const SelfType& src)
+ {
+ Clear();
+ if (src.IsEmpty() == false)
+ {
+ SetCapacity(src.GetSize());
+
+ for (ConstIterator it = src.Begin(); it != src.End(); ++it)
+ {
+ Add(*it);
+ }
+ }
+ }
+
+
+ // Remove all entries from the HashSet table.
+ void Clear()
+ {
+ if (pTable)
+ {
+ // Delete the entries.
+ for (UPInt i = 0, n = pTable->SizeMask; i <= n; i++)
+ {
+ Entry* e = &E(i);
+ if (!e->IsEmpty())
+ e->Clear();
+ }
+
+ Allocator::Free(pTable);
+ pTable = NULL;
+ }
+ }
+
+ // Returns true if the HashSet is empty.
+ bool IsEmpty() const
+ {
+ return pTable == NULL || pTable->EntryCount == 0;
+ }
+
+
+ // Set a new or existing value under the key, to the value.
+ // Pass a different class of 'key' so that assignment reference object
+ // can be passed instead of the actual object.
+ template<class CRef>
+ void Set(const CRef& key)
+ {
+ UPInt hashValue = HashF()(key);
+ SPInt index = (SPInt)-1;
+
+ if (pTable != NULL)
+ index = findIndexCore(key, hashValue & pTable->SizeMask);
+
+ if (index >= 0)
+ {
+ E(index).Value = key;
+ }
+ else
+ {
+ // Entry under key doesn't exist.
+ add(key, hashValue);
+ }
+ }
+
+ template<class CRef>
+ inline void Add(const CRef& key)
+ {
+ UPInt hashValue = HashF()(key);
+ add(key, hashValue);
+ }
+
+ // Remove by alternative key.
+ template<class K>
+ void RemoveAlt(const K& key)
+ {
+ if (pTable == NULL)
+ return;
+
+ UPInt hashValue = AltHashF()(key);
+ SPInt index = hashValue & pTable->SizeMask;
+
+ Entry* e = &E(index);
+
+ // If empty node or occupied by collider, we have nothing to remove.
+ if (e->IsEmpty() || (e->GetCachedHash(pTable->SizeMask) != (UPInt)index))
+ return;
+
+ // Save index
+ SPInt naturalIndex = index;
+ SPInt prevIndex = -1;
+
+ while ((e->GetCachedHash(pTable->SizeMask) != (UPInt)naturalIndex) || !(e->Value == key))
+ {
+ // Keep looking through the chain.
+ prevIndex = index;
+ index = e->NextInChain;
+ if (index == -1)
+ return; // End of chain, item not found
+ e = &E(index);
+ }
+
+ // Found it - our item is at index
+ if (naturalIndex == index)
+ {
+ // If we have a follower, move it to us
+ if (!e->IsEndOfChain())
+ {
+ Entry* enext = &E(e->NextInChain);
+ e->Clear();
+ new (e) Entry(*enext);
+ // Point us to the follower's cell that will be cleared
+ e = enext;
+ }
+ }
+ else
+ {
+ // We are not at natural index, so deal with the prev items next index
+ E(prevIndex).NextInChain = e->NextInChain;
+ }
+
+ // Clear us, of the follower cell that was moved.
+ e->Clear();
+ pTable->EntryCount --;
+ // Should we check the size to condense hash? ...
+ }
+
+ // Remove by main key.
+ template<class CRef>
+ void Remove(const CRef& key)
+ {
+ RemoveAlt(key);
+ }
+
+ // Retrieve the pointer to a value under the given key.
+ // - If there's no value under the key, then return NULL.
+ // - If there is a value, return the pointer.
+ template<class K>
+ C* Get(const K& key)
+ {
+ SPInt index = findIndex(key);
+ if (index >= 0)
+ return &E(index).Value;
+ return 0;
+ }
+
+ template<class K>
+ const C* Get(const K& key) const
+ {
+ SPInt index = findIndex(key);
+ if (index >= 0)
+ return &E(index).Value;
+ return 0;
+ }
+
+ // Alternative key versions of Get. Used by Hash.
+ template<class K>
+ const C* GetAlt(const K& key) const
+ {
+ SPInt index = findIndexAlt(key);
+ if (index >= 0)
+ return &E(index).Value;
+ return 0;
+ }
+
+ template<class K>
+ C* GetAlt(const K& key)
+ {
+ SPInt index = findIndexAlt(key);
+ if (index >= 0)
+ return &E(index).Value;
+ return 0;
+ }
+
+ template<class K>
+ bool GetAlt(const K& key, C* pval) const
+ {
+ SPInt index = findIndexAlt(key);
+ if (index >= 0)
+ {
+ if (pval)
+ *pval = E(index).Value;
+ return true;
+ }
+ return false;
+ }
+
+
+ UPInt GetSize() const
+ {
+ return pTable == NULL ? 0 : (UPInt)pTable->EntryCount;
+ }
+
+
+ // Resize the HashSet table to fit one more Entry. Often this
+ // doesn't involve any action.
+ void CheckExpand()
+ {
+ if (pTable == NULL)
+ {
+ // Initial creation of table. Make a minimum-sized table.
+ setRawCapacity(HashMinSize);
+ }
+ else if (pTable->EntryCount * 5 > (pTable->SizeMask + 1) * 4)
+ {
+ // pTable is more than 5/4 ths full. Expand.
+ setRawCapacity((pTable->SizeMask + 1) * 2);
+ }
+ }
+
+ // Hint the bucket count to >= n.
+ void Resize(UPInt n)
+ {
+ // Not really sure what this means in relation to
+ // STLport's hash_map... they say they "increase the
+ // bucket count to at least n" -- but does that mean
+ // their real capacity after Resize(n) is more like
+ // n*2 (since they do linked-list chaining within
+ // buckets?).
+ SetCapacity(n);
+ }
+
+ // Size the HashSet so that it can comfortably contain the given
+ // number of elements. If the HashSet already contains more
+ // elements than newSize, then this may be a no-op.
+ void SetCapacity(UPInt newSize)
+ {
+ UPInt newRawSize = (newSize * 5) / 4;
+ if (newRawSize <= GetSize())
+ return;
+ setRawCapacity(newRawSize);
+ }
+
+ // Disable inappropriate 'operator ->' warning on MSVC6.
+#ifdef OVR_CC_MSVC
+#if (OVR_CC_MSVC < 1300)
+# pragma warning(disable : 4284)
+#endif
+#endif
+
+ // Iterator API, like STL.
+ struct ConstIterator
+ {
+ const C& operator * () const
+ {
+ OVR_ASSERT(Index >= 0 && Index <= (SPInt)pHash->pTable->SizeMask);
+ return pHash->E(Index).Value;
+ }
+
+ const C* operator -> () const
+ {
+ OVR_ASSERT(Index >= 0 && Index <= (SPInt)pHash->pTable->SizeMask);
+ return &pHash->E(Index).Value;
+ }
+
+ void operator ++ ()
+ {
+ // Find next non-empty Entry.
+ if (Index <= (SPInt)pHash->pTable->SizeMask)
+ {
+ Index++;
+ while ((UPInt)Index <= pHash->pTable->SizeMask &&
+ pHash->E(Index).IsEmpty())
+ {
+ Index++;
+ }
+ }
+ }
+
+ bool operator == (const ConstIterator& it) const
+ {
+ if (IsEnd() && it.IsEnd())
+ {
+ return true;
+ }
+ else
+ {
+ return (pHash == it.pHash) && (Index == it.Index);
+ }
+ }
+
+ bool operator != (const ConstIterator& it) const
+ {
+ return ! (*this == it);
+ }
+
+
+ bool IsEnd() const
+ {
+ return (pHash == NULL) ||
+ (pHash->pTable == NULL) ||
+ (Index > (SPInt)pHash->pTable->SizeMask);
+ }
+
+ ConstIterator()
+ : pHash(NULL), Index(0)
+ { }
+
+ public:
+ // Constructor was intentionally made public to allow create
+ // iterator with arbitrary index.
+ ConstIterator(const SelfType* h, SPInt index)
+ : pHash(h), Index(index)
+ { }
+
+ const SelfType* GetContainer() const
+ {
+ return pHash;
+ }
+ SPInt GetIndex() const
+ {
+ return Index;
+ }
+
+ protected:
+ friend class HashSetBase<C, HashF, AltHashF, Allocator, Entry>;
+
+ const SelfType* pHash;
+ SPInt Index;
+ };
+
+ friend struct ConstIterator;
+
+
+ // Non-const Iterator; Get most of it from ConstIterator.
+ struct Iterator : public ConstIterator
+ {
+ // Allow non-const access to entries.
+ C& operator*() const
+ {
+ OVR_ASSERT(ConstIterator::Index >= 0 && ConstIterator::Index <= (SPInt)ConstIterator::pHash->pTable->SizeMask);
+ return const_cast<SelfType*>(ConstIterator::pHash)->E(ConstIterator::Index).Value;
+ }
+
+ C* operator->() const
+ {
+ return &(operator*());
+ }
+
+ Iterator()
+ : ConstIterator(NULL, 0)
+ { }
+
+ // Removes current element from Hash
+ void Remove()
+ {
+ RemoveAlt(operator*());
+ }
+
+ template <class K>
+ void RemoveAlt(const K& key)
+ {
+ SelfType* phash = const_cast<SelfType*>(ConstIterator::pHash);
+ //Entry* ee = &phash->E(ConstIterator::Index);
+ //const C& key = ee->Value;
+
+ UPInt hashValue = AltHashF()(key);
+ SPInt index = hashValue & phash->pTable->SizeMask;
+
+ Entry* e = &phash->E(index);
+
+ // If empty node or occupied by collider, we have nothing to remove.
+ if (e->IsEmpty() || (e->GetCachedHash(phash->pTable->SizeMask) != (UPInt)index))
+ return;
+
+ // Save index
+ SPInt naturalIndex = index;
+ SPInt prevIndex = -1;
+
+ while ((e->GetCachedHash(phash->pTable->SizeMask) != (UPInt)naturalIndex) || !(e->Value == key))
+ {
+ // Keep looking through the chain.
+ prevIndex = index;
+ index = e->NextInChain;
+ if (index == -1)
+ return; // End of chain, item not found
+ e = &phash->E(index);
+ }
+
+ if (index == (SPInt)ConstIterator::Index)
+ {
+ // Found it - our item is at index
+ if (naturalIndex == index)
+ {
+ // If we have a follower, move it to us
+ if (!e->IsEndOfChain())
+ {
+ Entry* enext = &phash->E(e->NextInChain);
+ e->Clear();
+ new (e) Entry(*enext);
+ // Point us to the follower's cell that will be cleared
+ e = enext;
+ --ConstIterator::Index;
+ }
+ }
+ else
+ {
+ // We are not at natural index, so deal with the prev items next index
+ phash->E(prevIndex).NextInChain = e->NextInChain;
+ }
+
+ // Clear us, of the follower cell that was moved.
+ e->Clear();
+ phash->pTable->EntryCount --;
+ }
+ else
+ OVR_ASSERT(0); //?
+ }
+
+ private:
+ friend class HashSetBase<C, HashF, AltHashF, Allocator, Entry>;
+
+ Iterator(SelfType* h, SPInt i0)
+ : ConstIterator(h, i0)
+ { }
+ };
+
+ friend struct Iterator;
+
+ Iterator Begin()
+ {
+ if (pTable == 0)
+ return Iterator(NULL, 0);
+
+ // Scan till we hit the First valid Entry.
+ UPInt i0 = 0;
+ while (i0 <= pTable->SizeMask && E(i0).IsEmpty())
+ {
+ i0++;
+ }
+ return Iterator(this, i0);
+ }
+ Iterator End() { return Iterator(NULL, 0); }
+
+ ConstIterator Begin() const { return const_cast<SelfType*>(this)->Begin(); }
+ ConstIterator End() const { return const_cast<SelfType*>(this)->End(); }
+
+ template<class K>
+ Iterator Find(const K& key)
+ {
+ SPInt index = findIndex(key);
+ if (index >= 0)
+ return Iterator(this, index);
+ return Iterator(NULL, 0);
+ }
+
+ template<class K>
+ Iterator FindAlt(const K& key)
+ {
+ SPInt index = findIndexAlt(key);
+ if (index >= 0)
+ return Iterator(this, index);
+ return Iterator(NULL, 0);
+ }
+
+ template<class K>
+ ConstIterator Find(const K& key) const { return const_cast<SelfType*>(this)->Find(key); }
+
+ template<class K>
+ ConstIterator FindAlt(const K& key) const { return const_cast<SelfType*>(this)->FindAlt(key); }
+
+private:
+ // Find the index of the matching Entry. If no match, then return -1.
+ template<class K>
+ SPInt findIndex(const K& key) const
+ {
+ if (pTable == NULL)
+ return -1;
+ UPInt hashValue = HashF()(key) & pTable->SizeMask;
+ return findIndexCore(key, hashValue);
+ }
+
+ template<class K>
+ SPInt findIndexAlt(const K& key) const
+ {
+ if (pTable == NULL)
+ return -1;
+ UPInt hashValue = AltHashF()(key) & pTable->SizeMask;
+ return findIndexCore(key, hashValue);
+ }
+
+ // Find the index of the matching Entry. If no match, then return -1.
+ template<class K>
+ SPInt findIndexCore(const K& key, UPInt hashValue) const
+ {
+ // Table must exist.
+ OVR_ASSERT(pTable != 0);
+ // Hash key must be 'and-ed' by the caller.
+ OVR_ASSERT((hashValue & ~pTable->SizeMask) == 0);
+
+ UPInt index = hashValue;
+ const Entry* e = &E(index);
+
+ // If empty or occupied by a collider, not found.
+ if (e->IsEmpty() || (e->GetCachedHash(pTable->SizeMask) != index))
+ return -1;
+
+ while(1)
+ {
+ OVR_ASSERT(e->GetCachedHash(pTable->SizeMask) == hashValue);
+
+ if (e->GetCachedHash(pTable->SizeMask) == hashValue && e->Value == key)
+ {
+ // Found it.
+ return index;
+ }
+ // Values can not be equal at this point.
+ // That would mean that the hash key for the same value differs.
+ OVR_ASSERT(!(e->Value == key));
+
+ // Keep looking through the chain.
+ index = e->NextInChain;
+ if (index == (UPInt)-1)
+ break; // end of chain
+
+ e = &E(index);
+ OVR_ASSERT(!e->IsEmpty());
+ }
+ return -1;
+ }
+
+
+ // Add a new value to the HashSet table, under the specified key.
+ template<class CRef>
+ void add(const CRef& key, UPInt hashValue)
+ {
+ CheckExpand();
+ hashValue &= pTable->SizeMask;
+
+ pTable->EntryCount++;
+
+ SPInt index = hashValue;
+ Entry* naturalEntry = &(E(index));
+
+ if (naturalEntry->IsEmpty())
+ {
+ // Put the new Entry in.
+ new (naturalEntry) Entry(key, -1);
+ }
+ else
+ {
+ // Find a blank spot.
+ SPInt blankIndex = index;
+ do {
+ blankIndex = (blankIndex + 1) & pTable->SizeMask;
+ } while(!E(blankIndex).IsEmpty());
+
+ Entry* blankEntry = &E(blankIndex);
+
+ if (naturalEntry->GetCachedHash(pTable->SizeMask) == (UPInt)index)
+ {
+ // Collision. Link into this chain.
+
+ // Move existing list head.
+ new (blankEntry) Entry(*naturalEntry); // placement new, copy ctor
+
+ // Put the new info in the natural Entry.
+ naturalEntry->Value = key;
+ naturalEntry->NextInChain = blankIndex;
+ }
+ else
+ {
+ // Existing Entry does not naturally
+ // belong in this slot. Existing
+ // Entry must be moved.
+
+ // Find natural location of collided element (i.e. root of chain)
+ SPInt collidedIndex = naturalEntry->GetCachedHash(pTable->SizeMask);
+ OVR_ASSERT(collidedIndex >= 0 && collidedIndex <= (SPInt)pTable->SizeMask);
+ for (;;)
+ {
+ Entry* e = &E(collidedIndex);
+ if (e->NextInChain == index)
+ {
+ // Here's where we need to splice.
+ new (blankEntry) Entry(*naturalEntry);
+ e->NextInChain = blankIndex;
+ break;
+ }
+ collidedIndex = e->NextInChain;
+ OVR_ASSERT(collidedIndex >= 0 && collidedIndex <= (SPInt)pTable->SizeMask);
+ }
+
+ // Put the new data in the natural Entry.
+ naturalEntry->Value = key;
+ naturalEntry->NextInChain = -1;
+ }
+ }
+
+ // Record hash value: has effect only if cached node is used.
+ naturalEntry->SetCachedHash(hashValue);
+ }
+
+ // Index access helpers.
+ Entry& E(UPInt index)
+ {
+ // Must have pTable and access needs to be within bounds.
+ OVR_ASSERT(index <= pTable->SizeMask);
+ return *(((Entry*) (pTable + 1)) + index);
+ }
+ const Entry& E(UPInt index) const
+ {
+ OVR_ASSERT(index <= pTable->SizeMask);
+ return *(((Entry*) (pTable + 1)) + index);
+ }
+
+
+ // Resize the HashSet table to the given size (Rehash the
+ // contents of the current table). The arg is the number of
+ // HashSet table entries, not the number of elements we should
+ // actually contain (which will be less than this).
+ void setRawCapacity(UPInt newSize)
+ {
+ if (newSize == 0)
+ {
+ // Special case.
+ Clear();
+ return;
+ }
+
+ // Minimum size; don't incur rehashing cost when expanding
+ // very small tables. Not that we perform this check before
+ // 'log2f' call to avoid fp exception with newSize == 1.
+ if (newSize < HashMinSize)
+ newSize = HashMinSize;
+ else
+ {
+ // Force newSize to be a power of two.
+ int bits = Alg::UpperBit(newSize-1) + 1; // Chop( Log2f((float)(newSize-1)) + 1);
+ OVR_ASSERT((UPInt(1) << bits) >= newSize);
+ newSize = UPInt(1) << bits;
+ }
+
+ SelfType newHash;
+ newHash.pTable = (TableType*)
+ Allocator::Alloc(
+ sizeof(TableType) + sizeof(Entry) * newSize);
+ // Need to do something on alloc failure!
+ OVR_ASSERT(newHash.pTable);
+
+ newHash.pTable->EntryCount = 0;
+ newHash.pTable->SizeMask = newSize - 1;
+ UPInt i, n;
+
+ // Mark all entries as empty.
+ for (i = 0; i < newSize; i++)
+ newHash.E(i).NextInChain = -2;
+
+ // Copy stuff to newHash
+ if (pTable)
+ {
+ for (i = 0, n = pTable->SizeMask; i <= n; i++)
+ {
+ Entry* e = &E(i);
+ if (e->IsEmpty() == false)
+ {
+ // Insert old Entry into new HashSet.
+ newHash.Add(e->Value);
+ // placement delete of old element
+ e->Clear();
+ }
+ }
+
+ // Delete our old data buffer.
+ Allocator::Free(pTable);
+ }
+
+ // Steal newHash's data.
+ pTable = newHash.pTable;
+ newHash.pTable = NULL;
+ }
+
+ struct TableType
+ {
+ UPInt EntryCount;
+ UPInt SizeMask;
+ // Entry array follows this structure
+ // in memory.
+ };
+ TableType* pTable;
+};
+
+
+
+//-----------------------------------------------------------------------------------
+template<class C, class HashF = FixedSizeHash<C>,
+ class AltHashF = HashF,
+ class Allocator = ContainerAllocator<C>,
+ class Entry = HashsetCachedEntry<C, HashF> >
+class HashSet : public HashSetBase<C, HashF, AltHashF, Allocator, Entry>
+{
+public:
+ typedef HashSetBase<C, HashF, AltHashF, Allocator, Entry> BaseType;
+ typedef HashSet<C, HashF, AltHashF, Allocator, Entry> SelfType;
+
+ HashSet() { }
+ HashSet(int sizeHint) : BaseType(sizeHint) { }
+ HashSet(const SelfType& src) : BaseType(src) { }
+ ~HashSet() { }
+
+ void operator = (const SelfType& src) { BaseType::Assign(src); }
+
+ // Set a new or existing value under the key, to the value.
+ // Pass a different class of 'key' so that assignment reference object
+ // can be passed instead of the actual object.
+ template<class CRef>
+ void Set(const CRef& key)
+ {
+ BaseType::Set(key);
+ }
+
+ template<class CRef>
+ inline void Add(const CRef& key)
+ {
+ BaseType::Add(key);
+ }
+
+ // Hint the bucket count to >= n.
+ void Resize(UPInt n)
+ {
+ BaseType::SetCapacity(n);
+ }
+
+ // Size the HashSet so that it can comfortably contain the given
+ // number of elements. If the HashSet already contains more
+ // elements than newSize, then this may be a no-op.
+ void SetCapacity(UPInt newSize)
+ {
+ BaseType::SetCapacity(newSize);
+ }
+
+};
+
+// HashSet with uncached hash code; declared for convenience.
+template<class C, class HashF = FixedSizeHash<C>,
+ class AltHashF = HashF,
+ class Allocator = ContainerAllocator<C> >
+class HashSetUncached : public HashSet<C, HashF, AltHashF, Allocator, HashsetEntry<C, HashF> >
+{
+public:
+
+ typedef HashSetUncached<C, HashF, AltHashF, Allocator> SelfType;
+ typedef HashSet<C, HashF, AltHashF, Allocator, HashsetEntry<C, HashF> > BaseType;
+
+ // Delegated constructors.
+ HashSetUncached() { }
+ HashSetUncached(int sizeHint) : BaseType(sizeHint) { }
+ HashSetUncached(const SelfType& src) : BaseType(src) { }
+ ~HashSetUncached() { }
+
+ void operator = (const SelfType& src)
+ {
+ BaseType::operator = (src);
+ }
+};
+
+
+//-----------------------------------------------------------------------------------
+// ***** Hash hash table implementation
+
+// Node for Hash - necessary so that Hash can delegate its implementation
+// to HashSet.
+template<class C, class U, class HashF>
+struct HashNode
+{
+ typedef HashNode<C, U, HashF> SelfType;
+ typedef C FirstType;
+ typedef U SecondType;
+
+ C First;
+ U Second;
+
+ // NodeRef is used to allow passing of elements into HashSet
+ // without using a temporary object.
+ struct NodeRef
+ {
+ const C* pFirst;
+ const U* pSecond;
+
+ NodeRef(const C& f, const U& s) : pFirst(&f), pSecond(&s) { }
+ NodeRef(const NodeRef& src) : pFirst(src.pFirst), pSecond(src.pSecond) { }
+
+ // Enable computation of ghash_node_hashf.
+ inline UPInt GetHash() const { return HashF()(*pFirst); }
+ // Necessary conversion to allow HashNode::operator == to work.
+ operator const C& () const { return *pFirst; }
+ };
+
+ // Note: No default constructor is necessary.
+ HashNode(const HashNode& src) : First(src.First), Second(src.Second) { }
+ HashNode(const NodeRef& src) : First(*src.pFirst), Second(*src.pSecond) { }
+ void operator = (const NodeRef& src) { First = *src.pFirst; Second = *src.pSecond; }
+
+ template<class K>
+ bool operator == (const K& src) const { return (First == src); }
+
+ template<class K>
+ static UPInt CalcHash(const K& data) { return HashF()(data); }
+ inline UPInt GetHash() const { return HashF()(First); }
+
+ // Hash functors used with this node. A separate functor is used for alternative
+ // key lookup so that it does not need to access the '.First' element.
+ struct NodeHashF
+ {
+ template<class K>
+ UPInt operator()(const K& data) const { return data.GetHash(); }
+ };
+ struct NodeAltHashF
+ {
+ template<class K>
+ UPInt operator()(const K& data) const { return HashNode<C,U,HashF>::CalcHash(data); }
+ };
+};
+
+
+
+// **** Extra hashset_entry types to allow NodeRef construction.
+
+// The big difference between the below types and the ones used in hash_set is that
+// these allow initializing the node with 'typename C::NodeRef& keyRef', which
+// is critical to avoid temporary node allocation on stack when using placement new.
+
+// Compact hash table Entry type that re-computes hash keys during hash traversal.
+// Good to use if the hash function is cheap or the hash value is already cached in C.
+template<class C, class HashF>
+class HashsetNodeEntry
+{
+public:
+ // Internal chaining for collisions.
+ SPInt NextInChain;
+ C Value;
+
+ HashsetNodeEntry()
+ : NextInChain(-2) { }
+ HashsetNodeEntry(const HashsetNodeEntry& e)
+ : NextInChain(e.NextInChain), Value(e.Value) { }
+ HashsetNodeEntry(const C& key, SPInt next)
+ : NextInChain(next), Value(key) { }
+ HashsetNodeEntry(const typename C::NodeRef& keyRef, SPInt next)
+ : NextInChain(next), Value(keyRef) { }
+
+ bool IsEmpty() const { return NextInChain == -2; }
+ bool IsEndOfChain() const { return NextInChain == -1; }
+ UPInt GetCachedHash(UPInt maskValue) const { return HashF()(Value) & maskValue; }
+ void SetCachedHash(UPInt hashValue) { OVR_UNUSED(hashValue); }
+
+ void Clear()
+ {
+ Value.~C(); // placement delete
+ NextInChain = -2;
+ }
+ // Free is only used from dtor of hash; Clear is used during regular operations:
+ // assignment, hash reallocations, value reassignments, so on.
+ void Free() { Clear(); }
+};
+
+// Hash table Entry type that caches the Entry hash value for nodes, so that it
+// does not need to be re-computed during access.
+template<class C, class HashF>
+class HashsetCachedNodeEntry
+{
+public:
+ // Internal chaining for collisions.
+ SPInt NextInChain;
+ UPInt HashValue;
+ C Value;
+
+ HashsetCachedNodeEntry()
+ : NextInChain(-2) { }
+ HashsetCachedNodeEntry(const HashsetCachedNodeEntry& e)
+ : NextInChain(e.NextInChain), HashValue(e.HashValue), Value(e.Value) { }
+ HashsetCachedNodeEntry(const C& key, SPInt next)
+ : NextInChain(next), Value(key) { }
+ HashsetCachedNodeEntry(const typename C::NodeRef& keyRef, SPInt next)
+ : NextInChain(next), Value(keyRef) { }
+
+ bool IsEmpty() const { return NextInChain == -2; }
+ bool IsEndOfChain() const { return NextInChain == -1; }
+ UPInt GetCachedHash(UPInt maskValue) const { OVR_UNUSED(maskValue); return HashValue; }
+ void SetCachedHash(UPInt hashValue) { HashValue = hashValue; }
+
+ void Clear()
+ {
+ Value.~C();
+ NextInChain = -2;
+ }
+ // Free is only used from dtor of hash; Clear is used during regular operations:
+ // assignment, hash reallocations, value reassignments, so on.
+ void Free() { Clear(); }
+};
+
+
+//-----------------------------------------------------------------------------------
+template<class C, class U,
+ class HashF = FixedSizeHash<C>,
+ class Allocator = ContainerAllocator<C>,
+ class HashNode = OVR::HashNode<C,U,HashF>,
+ class Entry = HashsetCachedNodeEntry<HashNode, typename HashNode::NodeHashF>,
+ class Container = HashSet<HashNode, typename HashNode::NodeHashF,
+ typename HashNode::NodeAltHashF, Allocator,
+ Entry> >
+class Hash
+{
+public:
+ OVR_MEMORY_REDEFINE_NEW(Hash)
+
+ // Types used for hash_set.
+ typedef U ValueType;
+ typedef Hash<C, U, HashF, Allocator, HashNode, Entry, Container> SelfType;
+
+ // Actual hash table itself, implemented as hash_set.
+ Container mHash;
+
+public:
+ Hash() { }
+ Hash(int sizeHint) : mHash(sizeHint) { }
+ Hash(const SelfType& src) : mHash(src.mHash) { }
+ ~Hash() { }
+
+ void operator = (const SelfType& src) { mHash = src.mHash; }
+
+ // Remove all entries from the Hash table.
+ inline void Clear() { mHash.Clear(); }
+ // Returns true if the Hash is empty.
+ inline bool IsEmpty() const { return mHash.IsEmpty(); }
+
+ // Access (set).
+ inline void Set(const C& key, const U& value)
+ {
+ typename HashNode::NodeRef e(key, value);
+ mHash.Set(e);
+ }
+ inline void Add(const C& key, const U& value)
+ {
+ typename HashNode::NodeRef e(key, value);
+ mHash.Add(e);
+ }
+
+ // Removes an element by clearing its Entry.
+ inline void Remove(const C& key)
+ {
+ mHash.RemoveAlt(key);
+ }
+ template<class K>
+ inline void RemoveAlt(const K& key)
+ {
+ mHash.RemoveAlt(key);
+ }
+
+ // Retrieve the value under the given key.
+ // - If there's no value under the key, then return false and leave *pvalue alone.
+ // - If there is a value, return true, and Set *Pvalue to the Entry's value.
+ // - If value == NULL, return true or false according to the presence of the key.
+ bool Get(const C& key, U* pvalue) const
+ {
+ const HashNode* p = mHash.GetAlt(key);
+ if (p)
+ {
+ if (pvalue)
+ *pvalue = p->Second;
+ return true;
+ }
+ return false;
+ }
+
+ template<class K>
+ bool GetAlt(const K& key, U* pvalue) const
+ {
+ const HashNode* p = mHash.GetAlt(key);
+ if (p)
+ {
+ if (pvalue)
+ *pvalue = p->Second;
+ return true;
+ }
+ return false;
+ }
+
+ // Retrieve the pointer to a value under the given key.
+ // - If there's no value under the key, then return NULL.
+ // - If there is a value, return the pointer.
+ inline U* Get(const C& key)
+ {
+ HashNode* p = mHash.GetAlt(key);
+ return p ? &p->Second : 0;
+ }
+ inline const U* Get(const C& key) const
+ {
+ const HashNode* p = mHash.GetAlt(key);
+ return p ? &p->Second : 0;
+ }
+
+ template<class K>
+ inline U* GetAlt(const K& key)
+ {
+ HashNode* p = mHash.GetAlt(key);
+ return p ? &p->Second : 0;
+ }
+ template<class K>
+ inline const U* GetAlt(const K& key) const
+ {
+ const HashNode* p = mHash.GetAlt(key);
+ return p ? &p->Second : 0;
+ }
+
+ // Sizing methods - delegate to Hash.
+ inline UPInt GetSize() const { return mHash.GetSize(); }
+ inline void Resize(UPInt n) { mHash.Resize(n); }
+ inline void SetCapacity(UPInt newSize) { mHash.SetCapacity(newSize); }
+
+ // Iterator API, like STL.
+ typedef typename Container::ConstIterator ConstIterator;
+ typedef typename Container::Iterator Iterator;
+
+ inline Iterator Begin() { return mHash.Begin(); }
+ inline Iterator End() { return mHash.End(); }
+ inline ConstIterator Begin() const { return mHash.Begin(); }
+ inline ConstIterator End() const { return mHash.End(); }
+
+ Iterator Find(const C& key) { return mHash.FindAlt(key); }
+ ConstIterator Find(const C& key) const { return mHash.FindAlt(key); }
+
+ template<class K>
+ Iterator FindAlt(const K& key) { return mHash.FindAlt(key); }
+ template<class K>
+ ConstIterator FindAlt(const K& key) const { return mHash.FindAlt(key); }
+};
+
+
+
+// Hash with uncached hash code; declared for convenience.
+template<class C, class U, class HashF = FixedSizeHash<C>, class Allocator = ContainerAllocator<C> >
+class HashUncached
+ : public Hash<C, U, HashF, Allocator, HashNode<C,U,HashF>,
+ HashsetNodeEntry<HashNode<C,U,HashF>, typename HashNode<C,U,HashF>::NodeHashF> >
+{
+public:
+ typedef HashUncached<C, U, HashF, Allocator> SelfType;
+ typedef Hash<C, U, HashF, Allocator, HashNode<C,U,HashF>,
+ HashsetNodeEntry<HashNode<C,U,HashF>,
+ typename HashNode<C,U,HashF>::NodeHashF> > BaseType;
+
+ // Delegated constructors.
+ HashUncached() { }
+ HashUncached(int sizeHint) : BaseType(sizeHint) { }
+ HashUncached(const SelfType& src) : BaseType(src) { }
+ ~HashUncached() { }
+ void operator = (const SelfType& src) { BaseType::operator = (src); }
+};
+
+
+
+// And identity hash in which keys serve as hash value. Can be uncached,
+// since hash computation is assumed cheap.
+template<class C, class U, class Allocator = ContainerAllocator<C>, class HashF = IdentityHash<C> >
+class HashIdentity
+ : public HashUncached<C, U, HashF, Allocator>
+{
+public:
+ typedef HashIdentity<C, U, Allocator, HashF> SelfType;
+ typedef HashUncached<C, U, HashF, Allocator> BaseType;
+
+ // Delegated constructors.
+ HashIdentity() { }
+ HashIdentity(int sizeHint) : BaseType(sizeHint) { }
+ HashIdentity(const SelfType& src) : BaseType(src) { }
+ ~HashIdentity() { }
+ void operator = (const SelfType& src) { BaseType::operator = (src); }
+};
+
+
+} // OVR
+
+
+#ifdef OVR_DEFINE_NEW
+#define new OVR_DEFINE_NEW
+#endif
+
+#endif
diff --git a/LibOVR/Src/Kernel/OVR_KeyCodes.h b/LibOVR/Src/Kernel/OVR_KeyCodes.h
index 647688a..5e0aa5e 100644
--- a/LibOVR/Src/Kernel/OVR_KeyCodes.h
+++ b/LibOVR/Src/Kernel/OVR_KeyCodes.h
@@ -1,240 +1,240 @@
-/************************************************************************************
-
-PublicHeader: OVR.h
-Filename : OVR_KeyCodes.h
-Content : Common keyboard constants
-Created : September 19, 2012
-
-Copyright : Copyright 2012 Oculus VR, Inc. All Rights reserved.
-
-Use of this software is subject to the terms of the Oculus license
-agreement provided at the time of installation or download, or which
-otherwise accompanies this software in either electronic or hard copy form.
-
-************************************************************************************/
-
-#ifndef OVR_KeyCodes_h
-#define OVR_KeyCodes_h
-
-namespace OVR {
-
-//-----------------------------------------------------------------------------------
-// ***** KeyCode
-
-// KeyCode enumeration defines platform-independent keyboard key constants.
-// Note that Key_A through Key_Z are mapped to capital ascii constants.
-
-enum KeyCode
-{
- // Key_None indicates that no key was specified.
- Key_None = 0,
-
- // A through Z and numbers 0 through 9.
- Key_A = 65,
- Key_B,
- Key_C,
- Key_D,
- Key_E,
- Key_F,
- Key_G,
- Key_H,
- Key_I,
- Key_J,
- Key_K,
- Key_L,
- Key_M,
- Key_N,
- Key_O,
- Key_P,
- Key_Q,
- Key_R,
- Key_S,
- Key_T,
- Key_U,
- Key_V,
- Key_W,
- Key_X,
- Key_Y,
- Key_Z,
- Key_Num0 = 48,
- Key_Num1,
- Key_Num2,
- Key_Num3,
- Key_Num4,
- Key_Num5,
- Key_Num6,
- Key_Num7,
- Key_Num8,
- Key_Num9,
-
- // Numeric keypad.
- Key_KP_0 = 0xa0,
- Key_KP_1,
- Key_KP_2,
- Key_KP_3,
- Key_KP_4,
- Key_KP_5,
- Key_KP_6,
- Key_KP_7,
- Key_KP_8,
- Key_KP_9,
- Key_KP_Multiply,
- Key_KP_Add,
- Key_KP_Enter,
- Key_KP_Subtract,
- Key_KP_Decimal,
- Key_KP_Divide,
-
- // Function keys.
- Key_F1 = 0xb0,
- Key_F2,
- Key_F3,
- Key_F4,
- Key_F5,
- Key_F6,
- Key_F7,
- Key_F8,
- Key_F9,
- Key_F10,
- Key_F11,
- Key_F12,
- Key_F13,
- Key_F14,
- Key_F15,
-
- // Other keys.
- Key_Backspace = 8,
- Key_Tab,
- Key_Clear = 12,
- Key_Return,
- Key_Shift = 16,
- Key_Control,
- Key_Alt,
- Key_Pause,
- Key_CapsLock = 20, // Toggle
- Key_Escape = 27,
- Key_Space = 32,
- Key_Quote = 39,
- Key_PageUp = 0xc0,
- Key_PageDown,
- Key_End,
- Key_Home,
- Key_Left,
- Key_Up,
- Key_Right,
- Key_Down,
- Key_Insert,
- Key_Delete,
- Key_Help,
-
- Key_Comma = 44,
- Key_Minus,
- Key_Slash = 47,
- Key_Period,
- Key_NumLock = 144, // Toggle
- Key_ScrollLock = 145, // Toggle
-
- Key_Semicolon = 59,
- Key_Equal = 61,
- Key_Bar = 192,
- Key_BracketLeft = 91,
- Key_Backslash,
- Key_BracketRight,
-
- Key_OEM_AX = 0xE1, // 'AX' key on Japanese AX keyboard
- Key_OEM_102 = 0xE2, // "<>" or "\|" on RT 102-key keyboard.
- Key_ICO_HELP = 0xE3, // Help key on ICO
- Key_ICO_00 = 0xE4, // 00 key on ICO
-
- Key_Meta,
-
- // Total number of keys.
- Key_CodeCount
-};
-
-
-//-----------------------------------------------------------------------------------
-
-class KeyModifiers
-{
-public:
- enum
- {
- Key_ShiftPressed = 0x01,
- Key_CtrlPressed = 0x02,
- Key_AltPressed = 0x04,
- Key_MetaPressed = 0x08,
- Key_CapsToggled = 0x10,
- Key_NumToggled = 0x20,
- Key_ScrollToggled = 0x40,
-
- Initialized_Bit = 0x80,
- Initialized_Mask = 0xFF
- };
- unsigned char States;
-
- KeyModifiers() : States(0) { }
- KeyModifiers(unsigned char st) : States((unsigned char)(st | Initialized_Bit)) { }
-
- void Reset() { States = 0; }
-
- bool IsShiftPressed() const { return (States & Key_ShiftPressed) != 0; }
- bool IsCtrlPressed() const { return (States & Key_CtrlPressed) != 0; }
- bool IsAltPressed() const { return (States & Key_AltPressed) != 0; }
- bool IsMetaPressed() const { return (States & Key_MetaPressed) != 0; }
- bool IsCapsToggled() const { return (States & Key_CapsToggled) != 0; }
- bool IsNumToggled() const { return (States & Key_NumToggled) != 0; }
- bool IsScrollToggled() const{ return (States & Key_ScrollToggled) != 0; }
-
- void SetShiftPressed(bool v = true) { (v) ? States |= Key_ShiftPressed : States &= ~Key_ShiftPressed; }
- void SetCtrlPressed(bool v = true) { (v) ? States |= Key_CtrlPressed : States &= ~Key_CtrlPressed; }
- void SetAltPressed(bool v = true) { (v) ? States |= Key_AltPressed : States &= ~Key_AltPressed; }
- void SetMetaPressed(bool v = true) { (v) ? States |= Key_MetaPressed : States &= ~Key_MetaPressed; }
- void SetCapsToggled(bool v = true) { (v) ? States |= Key_CapsToggled : States &= ~Key_CapsToggled; }
- void SetNumToggled(bool v = true) { (v) ? States |= Key_NumToggled : States &= ~Key_NumToggled; }
- void SetScrollToggled(bool v = true) { (v) ? States |= Key_ScrollToggled: States &= ~Key_ScrollToggled; }
-
- bool IsInitialized() const { return (States & Initialized_Mask) != 0; }
-};
-
-
-//-----------------------------------------------------------------------------------
-
-/*
-enum PadKeyCode
-{
- Pad_None, // Indicates absence of key code.
- Pad_Back,
- Pad_Start,
- Pad_A,
- Pad_B,
- Pad_X,
- Pad_Y,
- Pad_R1, // RightShoulder;
- Pad_L1, // LeftShoulder;
- Pad_R2, // RightTrigger;
- Pad_L2, // LeftTrigger;
- Pad_Up,
- Pad_Down,
- Pad_Right,
- Pad_Left,
- Pad_Plus,
- Pad_Minus,
- Pad_1,
- Pad_2,
- Pad_H,
- Pad_C,
- Pad_Z,
- Pad_O,
- Pad_T,
- Pad_S,
- Pad_Select,
- Pad_Home,
- Pad_RT, // RightThumb;
- Pad_LT // LeftThumb;
-};
-*/
-
-} // OVR
-
-#endif
+/************************************************************************************
+
+PublicHeader: OVR.h
+Filename : OVR_KeyCodes.h
+Content : Common keyboard constants
+Created : September 19, 2012
+
+Copyright : Copyright 2012 Oculus VR, Inc. All Rights reserved.
+
+Use of this software is subject to the terms of the Oculus license
+agreement provided at the time of installation or download, or which
+otherwise accompanies this software in either electronic or hard copy form.
+
+************************************************************************************/
+
+#ifndef OVR_KeyCodes_h
+#define OVR_KeyCodes_h
+
+namespace OVR {
+
+//-----------------------------------------------------------------------------------
+// ***** KeyCode
+
+// KeyCode enumeration defines platform-independent keyboard key constants.
+// Note that Key_A through Key_Z are mapped to capital ascii constants.
+
+enum KeyCode
+{
+ // Key_None indicates that no key was specified.
+ Key_None = 0,
+
+ // A through Z and numbers 0 through 9.
+ Key_A = 65,
+ Key_B,
+ Key_C,
+ Key_D,
+ Key_E,
+ Key_F,
+ Key_G,
+ Key_H,
+ Key_I,
+ Key_J,
+ Key_K,
+ Key_L,
+ Key_M,
+ Key_N,
+ Key_O,
+ Key_P,
+ Key_Q,
+ Key_R,
+ Key_S,
+ Key_T,
+ Key_U,
+ Key_V,
+ Key_W,
+ Key_X,
+ Key_Y,
+ Key_Z,
+ Key_Num0 = 48,
+ Key_Num1,
+ Key_Num2,
+ Key_Num3,
+ Key_Num4,
+ Key_Num5,
+ Key_Num6,
+ Key_Num7,
+ Key_Num8,
+ Key_Num9,
+
+ // Numeric keypad.
+ Key_KP_0 = 0xa0,
+ Key_KP_1,
+ Key_KP_2,
+ Key_KP_3,
+ Key_KP_4,
+ Key_KP_5,
+ Key_KP_6,
+ Key_KP_7,
+ Key_KP_8,
+ Key_KP_9,
+ Key_KP_Multiply,
+ Key_KP_Add,
+ Key_KP_Enter,
+ Key_KP_Subtract,
+ Key_KP_Decimal,
+ Key_KP_Divide,
+
+ // Function keys.
+ Key_F1 = 0xb0,
+ Key_F2,
+ Key_F3,
+ Key_F4,
+ Key_F5,
+ Key_F6,
+ Key_F7,
+ Key_F8,
+ Key_F9,
+ Key_F10,
+ Key_F11,
+ Key_F12,
+ Key_F13,
+ Key_F14,
+ Key_F15,
+
+ // Other keys.
+ Key_Backspace = 8,
+ Key_Tab,
+ Key_Clear = 12,
+ Key_Return,
+ Key_Shift = 16,
+ Key_Control,
+ Key_Alt,
+ Key_Pause,
+ Key_CapsLock = 20, // Toggle
+ Key_Escape = 27,
+ Key_Space = 32,
+ Key_Quote = 39,
+ Key_PageUp = 0xc0,
+ Key_PageDown,
+ Key_End,
+ Key_Home,
+ Key_Left,
+ Key_Up,
+ Key_Right,
+ Key_Down,
+ Key_Insert,
+ Key_Delete,
+ Key_Help,
+
+ Key_Comma = 44,
+ Key_Minus,
+ Key_Slash = 47,
+ Key_Period,
+ Key_NumLock = 144, // Toggle
+ Key_ScrollLock = 145, // Toggle
+
+ Key_Semicolon = 59,
+ Key_Equal = 61,
+ Key_Bar = 192,
+ Key_BracketLeft = 91,
+ Key_Backslash,
+ Key_BracketRight,
+
+ Key_OEM_AX = 0xE1, // 'AX' key on Japanese AX keyboard
+ Key_OEM_102 = 0xE2, // "<>" or "\|" on RT 102-key keyboard.
+ Key_ICO_HELP = 0xE3, // Help key on ICO
+ Key_ICO_00 = 0xE4, // 00 key on ICO
+
+ Key_Meta,
+
+ // Total number of keys.
+ Key_CodeCount
+};
+
+
+//-----------------------------------------------------------------------------------
+
+class KeyModifiers
+{
+public:
+ enum
+ {
+ Key_ShiftPressed = 0x01,
+ Key_CtrlPressed = 0x02,
+ Key_AltPressed = 0x04,
+ Key_MetaPressed = 0x08,
+ Key_CapsToggled = 0x10,
+ Key_NumToggled = 0x20,
+ Key_ScrollToggled = 0x40,
+
+ Initialized_Bit = 0x80,
+ Initialized_Mask = 0xFF
+ };
+ unsigned char States;
+
+ KeyModifiers() : States(0) { }
+ KeyModifiers(unsigned char st) : States((unsigned char)(st | Initialized_Bit)) { }
+
+ void Reset() { States = 0; }
+
+ bool IsShiftPressed() const { return (States & Key_ShiftPressed) != 0; }
+ bool IsCtrlPressed() const { return (States & Key_CtrlPressed) != 0; }
+ bool IsAltPressed() const { return (States & Key_AltPressed) != 0; }
+ bool IsMetaPressed() const { return (States & Key_MetaPressed) != 0; }
+ bool IsCapsToggled() const { return (States & Key_CapsToggled) != 0; }
+ bool IsNumToggled() const { return (States & Key_NumToggled) != 0; }
+ bool IsScrollToggled() const{ return (States & Key_ScrollToggled) != 0; }
+
+ void SetShiftPressed(bool v = true) { (v) ? States |= Key_ShiftPressed : States &= ~Key_ShiftPressed; }
+ void SetCtrlPressed(bool v = true) { (v) ? States |= Key_CtrlPressed : States &= ~Key_CtrlPressed; }
+ void SetAltPressed(bool v = true) { (v) ? States |= Key_AltPressed : States &= ~Key_AltPressed; }
+ void SetMetaPressed(bool v = true) { (v) ? States |= Key_MetaPressed : States &= ~Key_MetaPressed; }
+ void SetCapsToggled(bool v = true) { (v) ? States |= Key_CapsToggled : States &= ~Key_CapsToggled; }
+ void SetNumToggled(bool v = true) { (v) ? States |= Key_NumToggled : States &= ~Key_NumToggled; }
+ void SetScrollToggled(bool v = true) { (v) ? States |= Key_ScrollToggled: States &= ~Key_ScrollToggled; }
+
+ bool IsInitialized() const { return (States & Initialized_Mask) != 0; }
+};
+
+
+//-----------------------------------------------------------------------------------
+
+/*
+enum PadKeyCode
+{
+ Pad_None, // Indicates absence of key code.
+ Pad_Back,
+ Pad_Start,
+ Pad_A,
+ Pad_B,
+ Pad_X,
+ Pad_Y,
+ Pad_R1, // RightShoulder;
+ Pad_L1, // LeftShoulder;
+ Pad_R2, // RightTrigger;
+ Pad_L2, // LeftTrigger;
+ Pad_Up,
+ Pad_Down,
+ Pad_Right,
+ Pad_Left,
+ Pad_Plus,
+ Pad_Minus,
+ Pad_1,
+ Pad_2,
+ Pad_H,
+ Pad_C,
+ Pad_Z,
+ Pad_O,
+ Pad_T,
+ Pad_S,
+ Pad_Select,
+ Pad_Home,
+ Pad_RT, // RightThumb;
+ Pad_LT // LeftThumb;
+};
+*/
+
+} // OVR
+
+#endif
diff --git a/LibOVR/Src/Kernel/OVR_List.h b/LibOVR/Src/Kernel/OVR_List.h
index 0292f51..4b32f49 100644
--- a/LibOVR/Src/Kernel/OVR_List.h
+++ b/LibOVR/Src/Kernel/OVR_List.h
@@ -1,325 +1,325 @@
-/************************************************************************************
-
-PublicHeader: OVR
-Filename : OVR_List.h
-Content : Template implementation for doubly-connected linked List
-Created : September 19, 2012
-Notes :
-
-Copyright : Copyright 2012 Oculus VR, Inc. All Rights reserved.
-
-Use of this software is subject to the terms of the Oculus license
-agreement provided at the time of installation or download, or which
-otherwise accompanies this software in either electronic or hard copy form.
-
-************************************************************************************/
-
-#ifndef OVR_List_h
-#define OVR_List_h
-
-#include "OVR_Types.h"
-
-namespace OVR {
-
-//-----------------------------------------------------------------------------------
-// ***** ListNode
-//
-// Base class for the elements of the intrusive linked list.
-// To store elements in the List do:
-//
-// struct MyData : ListNode<MyData>
-// {
-// . . .
-// };
-
-template<class T>
-struct ListNode
-{
- union {
- T* pPrev;
- void* pVoidPrev;
- };
- union {
- T* pNext;
- void* pVoidNext;
- };
-
- void RemoveNode()
- {
- pPrev->pNext = pNext;
- pNext->pPrev = pPrev;
- }
-
- // Removes us from the list and inserts pnew there instead.
- void ReplaceNodeWith(T* pnew)
- {
- pPrev->pNext = pnew;
- pNext->pPrev = pnew;
- pnew->pPrev = pPrev;
- pnew->pNext = pNext;
- }
-
- // Inserts the argument linked list node after us in the list.
- void InsertNodeAfter(T* p)
- {
- p->pPrev = pNext->pPrev; // this
- p->pNext = pNext;
- pNext->pPrev = p;
- pNext = p;
- }
- // Inserts the argument linked list node before us in the list.
- void InsertNodeBefore(T* p)
- {
- p->pNext = pNext->pPrev; // this
- p->pPrev = pPrev;
- pPrev->pNext = p;
- pPrev = p;
- }
-
- void Alloc_MoveTo(ListNode<T>* pdest)
- {
- pdest->pNext = pNext;
- pdest->pPrev = pPrev;
- pPrev->pNext = (T*)pdest;
- pNext->pPrev = (T*)pdest;
- }
-};
-
-
-//------------------------------------------------------------------------
-// ***** List
-//
-// Doubly linked intrusive list.
-// The data type must be derived from ListNode.
-//
-// Adding: PushFront(), PushBack().
-// Removing: Remove() - the element must be in the list!
-// Moving: BringToFront(), SendToBack() - the element must be in the list!
-//
-// Iterating:
-// MyData* data = MyList.GetFirst();
-// while (!MyList.IsNull(data))
-// {
-// . . .
-// data = MyList.GetNext(data);
-// }
-//
-// Removing:
-// MyData* data = MyList.GetFirst();
-// while (!MyList.IsNull(data))
-// {
-// MyData* next = MyList.GetNext(data);
-// if (ToBeRemoved(data))
-// MyList.Remove(data);
-// data = next;
-// }
-//
-
-// List<> represents a doubly-linked list if 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.
-
-template<class T, class B = T> class List
-{
-public:
- typedef T ValueType;
-
- List()
- {
- Root.pNext = Root.pPrev = (ValueType*)&Root;
- }
-
- void Clear()
- {
- Root.pNext = Root.pPrev = (ValueType*)&Root;
- }
-
- const ValueType* GetFirst() const { return (const ValueType*)Root.pNext; }
- const ValueType* GetLast () const { return (const ValueType*)Root.pPrev; }
- ValueType* GetFirst() { return (ValueType*)Root.pNext; }
- ValueType* GetLast () { return (ValueType*)Root.pPrev; }
-
- // Determine if list is empty (i.e.) points to itself.
- // Go through void* access to avoid issues with strict-aliasing optimizing out the
- // access after RemoveNode(), etc.
- bool IsEmpty() const { return Root.pVoidNext == (const T*)(const B*)&Root; }
- bool IsFirst(const ValueType* p) const { return p == Root.pNext; }
- bool IsLast (const ValueType* p) const { return p == Root.pPrev; }
- bool IsNull (const ValueType* p) const { return p == (const T*)(const B*)&Root; }
-
- inline static const ValueType* GetPrev(const ValueType* p) { return (const ValueType*)p->pPrev; }
- inline static const ValueType* GetNext(const ValueType* p) { return (const ValueType*)p->pNext; }
- inline static ValueType* GetPrev( ValueType* p) { return (ValueType*)p->pPrev; }
- inline static ValueType* GetNext( ValueType* p) { return (ValueType*)p->pNext; }
-
- void PushFront(ValueType* p)
- {
- p->pNext = Root.pNext;
- p->pPrev = (ValueType*)&Root;
- Root.pNext->pPrev = p;
- Root.pNext = p;
- }
-
- void PushBack(ValueType* p)
- {
- p->pPrev = Root.pPrev;
- p->pNext = (ValueType*)&Root;
- Root.pPrev->pNext = p;
- Root.pPrev = p;
- }
-
- static void Remove(ValueType* p)
- {
- p->pPrev->pNext = p->pNext;
- p->pNext->pPrev = p->pPrev;
- }
-
- void BringToFront(ValueType* p)
- {
- Remove(p);
- PushFront(p);
- }
-
- void SendToBack(ValueType* p)
- {
- Remove(p);
- PushBack(p);
- }
-
- // Appends the contents of the argument list to the front of this list;
- // items are removed from the argument list.
- void PushListToFront(List<T>& src)
- {
- if (!src.IsEmpty())
- {
- ValueType* pfirst = src.GetFirst();
- ValueType* plast = src.GetLast();
- src.Clear();
- plast->pNext = Root.pNext;
- pfirst->pPrev = (ValueType*)&Root;
- Root.pNext->pPrev = plast;
- Root.pNext = pfirst;
- }
- }
-
- void PushListToBack(List<T>& src)
- {
- if (!src.IsEmpty())
- {
- ValueType* pfirst = src.GetFirst();
- ValueType* plast = src.GetLast();
- src.Clear();
- plast->pNext = (ValueType*)&Root;
- pfirst->pPrev = Root.pPrev;
- Root.pPrev->pNext = pfirst;
- Root.pPrev = plast;
- }
- }
-
- // Removes all source list items after (and including) the 'pfirst' node from the
- // source list and adds them to out list.
- void PushFollowingListItemsToFront(List<T>& src, ValueType *pfirst)
- {
- if (pfirst != &src.Root)
- {
- ValueType *plast = src.Root.pPrev;
-
- // Remove list remainder from source.
- pfirst->pPrev->pNext = (ValueType*)&src.Root;
- src.Root.pPrev = pfirst->pPrev;
- // Add the rest of the items to list.
- plast->pNext = Root.pNext;
- pfirst->pPrev = (ValueType*)&Root;
- Root.pNext->pPrev = plast;
- Root.pNext = pfirst;
- }
- }
-
- // Removes all source list items up to but NOT including the 'pend' node from the
- // source list and adds them to out list.
- void PushPrecedingListItemsToFront(List<T>& src, ValueType *ptail)
- {
- if (src.GetFirst() != ptail)
- {
- ValueType *pfirst = src.Root.pNext;
- ValueType *plast = ptail->pPrev;
-
- // Remove list remainder from source.
- ptail->pPrev = (ValueType*)&src.Root;
- src.Root.pNext = ptail;
-
- // Add the rest of the items to list.
- plast->pNext = Root.pNext;
- pfirst->pPrev = (ValueType*)&Root;
- Root.pNext->pPrev = plast;
- Root.pNext = pfirst;
- }
- }
-
-
- // Removes a range of source list items starting at 'pfirst' and up to, but not including 'pend',
- // and adds them to out list. Note that source items MUST already be in the list.
- void PushListItemsToFront(ValueType *pfirst, ValueType *pend)
- {
- if (pfirst != pend)
- {
- ValueType *plast = pend->pPrev;
-
- // Remove list remainder from source.
- pfirst->pPrev->pNext = pend;
- pend->pPrev = pfirst->pPrev;
- // Add the rest of the items to list.
- plast->pNext = Root.pNext;
- pfirst->pPrev = (ValueType*)&Root;
- Root.pNext->pPrev = plast;
- Root.pNext = pfirst;
- }
- }
-
-
- void Alloc_MoveTo(List<T>* pdest)
- {
- if (IsEmpty())
- pdest->Clear();
- else
- {
- pdest->Root.pNext = Root.pNext;
- pdest->Root.pPrev = Root.pPrev;
-
- Root.pNext->pPrev = (ValueType*)&pdest->Root;
- Root.pPrev->pNext = (ValueType*)&pdest->Root;
- }
- }
-
-
-private:
- // Copying is prohibited
- List(const List<T>&);
- const List<T>& operator = (const List<T>&);
-
- ListNode<B> Root;
-};
-
-
-//------------------------------------------------------------------------
-// ***** FreeListElements
-//
-// Remove all elements in the list and free them in the allocator
-
-template<class List, class Allocator>
-void FreeListElements(List& list, Allocator& allocator)
-{
- typename List::ValueType* self = list.GetFirst();
- while(!list.IsNull(self))
- {
- typename List::ValueType* next = list.GetNext(self);
- allocator.Free(self);
- self = next;
- }
- list.Clear();
-}
-
-} // OVR
-
-#endif
+/************************************************************************************
+
+PublicHeader: OVR
+Filename : OVR_List.h
+Content : Template implementation for doubly-connected linked List
+Created : September 19, 2012
+Notes :
+
+Copyright : Copyright 2012 Oculus VR, Inc. All Rights reserved.
+
+Use of this software is subject to the terms of the Oculus license
+agreement provided at the time of installation or download, or which
+otherwise accompanies this software in either electronic or hard copy form.
+
+************************************************************************************/
+
+#ifndef OVR_List_h
+#define OVR_List_h
+
+#include "OVR_Types.h"
+
+namespace OVR {
+
+//-----------------------------------------------------------------------------------
+// ***** ListNode
+//
+// Base class for the elements of the intrusive linked list.
+// To store elements in the List do:
+//
+// struct MyData : ListNode<MyData>
+// {
+// . . .
+// };
+
+template<class T>
+struct ListNode
+{
+ union {
+ T* pPrev;
+ void* pVoidPrev;
+ };
+ union {
+ T* pNext;
+ void* pVoidNext;
+ };
+
+ void RemoveNode()
+ {
+ pPrev->pNext = pNext;
+ pNext->pPrev = pPrev;
+ }
+
+ // Removes us from the list and inserts pnew there instead.
+ void ReplaceNodeWith(T* pnew)
+ {
+ pPrev->pNext = pnew;
+ pNext->pPrev = pnew;
+ pnew->pPrev = pPrev;
+ pnew->pNext = pNext;
+ }
+
+ // Inserts the argument linked list node after us in the list.
+ void InsertNodeAfter(T* p)
+ {
+ p->pPrev = pNext->pPrev; // this
+ p->pNext = pNext;
+ pNext->pPrev = p;
+ pNext = p;
+ }
+ // Inserts the argument linked list node before us in the list.
+ void InsertNodeBefore(T* p)
+ {
+ p->pNext = pNext->pPrev; // this
+ p->pPrev = pPrev;
+ pPrev->pNext = p;
+ pPrev = p;
+ }
+
+ void Alloc_MoveTo(ListNode<T>* pdest)
+ {
+ pdest->pNext = pNext;
+ pdest->pPrev = pPrev;
+ pPrev->pNext = (T*)pdest;
+ pNext->pPrev = (T*)pdest;
+ }
+};
+
+
+//------------------------------------------------------------------------
+// ***** List
+//
+// Doubly linked intrusive list.
+// The data type must be derived from ListNode.
+//
+// Adding: PushFront(), PushBack().
+// Removing: Remove() - the element must be in the list!
+// Moving: BringToFront(), SendToBack() - the element must be in the list!
+//
+// Iterating:
+// MyData* data = MyList.GetFirst();
+// while (!MyList.IsNull(data))
+// {
+// . . .
+// data = MyList.GetNext(data);
+// }
+//
+// Removing:
+// MyData* data = MyList.GetFirst();
+// while (!MyList.IsNull(data))
+// {
+// MyData* next = MyList.GetNext(data);
+// if (ToBeRemoved(data))
+// MyList.Remove(data);
+// data = next;
+// }
+//
+
+// List<> represents a doubly-linked list if 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.
+
+template<class T, class B = T> class List
+{
+public:
+ typedef T ValueType;
+
+ List()
+ {
+ Root.pNext = Root.pPrev = (ValueType*)&Root;
+ }
+
+ void Clear()
+ {
+ Root.pNext = Root.pPrev = (ValueType*)&Root;
+ }
+
+ const ValueType* GetFirst() const { return (const ValueType*)Root.pNext; }
+ const ValueType* GetLast () const { return (const ValueType*)Root.pPrev; }
+ ValueType* GetFirst() { return (ValueType*)Root.pNext; }
+ ValueType* GetLast () { return (ValueType*)Root.pPrev; }
+
+ // Determine if list is empty (i.e.) points to itself.
+ // Go through void* access to avoid issues with strict-aliasing optimizing out the
+ // access after RemoveNode(), etc.
+ bool IsEmpty() const { return Root.pVoidNext == (const T*)(const B*)&Root; }
+ bool IsFirst(const ValueType* p) const { return p == Root.pNext; }
+ bool IsLast (const ValueType* p) const { return p == Root.pPrev; }
+ bool IsNull (const ValueType* p) const { return p == (const T*)(const B*)&Root; }
+
+ inline static const ValueType* GetPrev(const ValueType* p) { return (const ValueType*)p->pPrev; }
+ inline static const ValueType* GetNext(const ValueType* p) { return (const ValueType*)p->pNext; }
+ inline static ValueType* GetPrev( ValueType* p) { return (ValueType*)p->pPrev; }
+ inline static ValueType* GetNext( ValueType* p) { return (ValueType*)p->pNext; }
+
+ void PushFront(ValueType* p)
+ {
+ p->pNext = Root.pNext;
+ p->pPrev = (ValueType*)&Root;
+ Root.pNext->pPrev = p;
+ Root.pNext = p;
+ }
+
+ void PushBack(ValueType* p)
+ {
+ p->pPrev = Root.pPrev;
+ p->pNext = (ValueType*)&Root;
+ Root.pPrev->pNext = p;
+ Root.pPrev = p;
+ }
+
+ static void Remove(ValueType* p)
+ {
+ p->pPrev->pNext = p->pNext;
+ p->pNext->pPrev = p->pPrev;
+ }
+
+ void BringToFront(ValueType* p)
+ {
+ Remove(p);
+ PushFront(p);
+ }
+
+ void SendToBack(ValueType* p)
+ {
+ Remove(p);
+ PushBack(p);
+ }
+
+ // Appends the contents of the argument list to the front of this list;
+ // items are removed from the argument list.
+ void PushListToFront(List<T>& src)
+ {
+ if (!src.IsEmpty())
+ {
+ ValueType* pfirst = src.GetFirst();
+ ValueType* plast = src.GetLast();
+ src.Clear();
+ plast->pNext = Root.pNext;
+ pfirst->pPrev = (ValueType*)&Root;
+ Root.pNext->pPrev = plast;
+ Root.pNext = pfirst;
+ }
+ }
+
+ void PushListToBack(List<T>& src)
+ {
+ if (!src.IsEmpty())
+ {
+ ValueType* pfirst = src.GetFirst();
+ ValueType* plast = src.GetLast();
+ src.Clear();
+ plast->pNext = (ValueType*)&Root;
+ pfirst->pPrev = Root.pPrev;
+ Root.pPrev->pNext = pfirst;
+ Root.pPrev = plast;
+ }
+ }
+
+ // Removes all source list items after (and including) the 'pfirst' node from the
+ // source list and adds them to out list.
+ void PushFollowingListItemsToFront(List<T>& src, ValueType *pfirst)
+ {
+ if (pfirst != &src.Root)
+ {
+ ValueType *plast = src.Root.pPrev;
+
+ // Remove list remainder from source.
+ pfirst->pPrev->pNext = (ValueType*)&src.Root;
+ src.Root.pPrev = pfirst->pPrev;
+ // Add the rest of the items to list.
+ plast->pNext = Root.pNext;
+ pfirst->pPrev = (ValueType*)&Root;
+ Root.pNext->pPrev = plast;
+ Root.pNext = pfirst;
+ }
+ }
+
+ // Removes all source list items up to but NOT including the 'pend' node from the
+ // source list and adds them to out list.
+ void PushPrecedingListItemsToFront(List<T>& src, ValueType *ptail)
+ {
+ if (src.GetFirst() != ptail)
+ {
+ ValueType *pfirst = src.Root.pNext;
+ ValueType *plast = ptail->pPrev;
+
+ // Remove list remainder from source.
+ ptail->pPrev = (ValueType*)&src.Root;
+ src.Root.pNext = ptail;
+
+ // Add the rest of the items to list.
+ plast->pNext = Root.pNext;
+ pfirst->pPrev = (ValueType*)&Root;
+ Root.pNext->pPrev = plast;
+ Root.pNext = pfirst;
+ }
+ }
+
+
+ // Removes a range of source list items starting at 'pfirst' and up to, but not including 'pend',
+ // and adds them to out list. Note that source items MUST already be in the list.
+ void PushListItemsToFront(ValueType *pfirst, ValueType *pend)
+ {
+ if (pfirst != pend)
+ {
+ ValueType *plast = pend->pPrev;
+
+ // Remove list remainder from source.
+ pfirst->pPrev->pNext = pend;
+ pend->pPrev = pfirst->pPrev;
+ // Add the rest of the items to list.
+ plast->pNext = Root.pNext;
+ pfirst->pPrev = (ValueType*)&Root;
+ Root.pNext->pPrev = plast;
+ Root.pNext = pfirst;
+ }
+ }
+
+
+ void Alloc_MoveTo(List<T>* pdest)
+ {
+ if (IsEmpty())
+ pdest->Clear();
+ else
+ {
+ pdest->Root.pNext = Root.pNext;
+ pdest->Root.pPrev = Root.pPrev;
+
+ Root.pNext->pPrev = (ValueType*)&pdest->Root;
+ Root.pPrev->pNext = (ValueType*)&pdest->Root;
+ }
+ }
+
+
+private:
+ // Copying is prohibited
+ List(const List<T>&);
+ const List<T>& operator = (const List<T>&);
+
+ ListNode<B> Root;
+};
+
+
+//------------------------------------------------------------------------
+// ***** FreeListElements
+//
+// Remove all elements in the list and free them in the allocator
+
+template<class List, class Allocator>
+void FreeListElements(List& list, Allocator& allocator)
+{
+ typename List::ValueType* self = list.GetFirst();
+ while(!list.IsNull(self))
+ {
+ typename List::ValueType* next = list.GetNext(self);
+ allocator.Free(self);
+ self = next;
+ }
+ list.Clear();
+}
+
+} // OVR
+
+#endif
diff --git a/LibOVR/Src/Kernel/OVR_Log.cpp b/LibOVR/Src/Kernel/OVR_Log.cpp
index baede98..255abcc 100644
--- a/LibOVR/Src/Kernel/OVR_Log.cpp
+++ b/LibOVR/Src/Kernel/OVR_Log.cpp
@@ -1,173 +1,173 @@
-/************************************************************************************
-
-Filename : OVR_Log.cpp
-Content : Logging support
-Created : September 19, 2012
-Notes :
-
-Copyright : Copyright 2012 Oculus VR, Inc. All Rights reserved.
-
-Use of this software is subject to the terms of the Oculus license
-agreement provided at the time of installation or download, or which
-otherwise accompanies this software in either electronic or hard copy form.
-
-************************************************************************************/
-
-#include "OVR_Log.h"
-#include "OVR_Std.h"
-#include <stdarg.h>
-#include <stdio.h>
-
-#if defined(OVR_OS_WIN32)
-#include <windows.h>
-#elif defined(OVR_OS_ANDROID)
-#include <android/log.h>
-#endif
-
-namespace OVR {
-
-// Global Log pointer.
-Log* volatile OVR_GlobalLog = 0;
-
-//-----------------------------------------------------------------------------------
-// ***** Log Implementation
-
-Log::~Log()
-{
- // Clear out global log
- if (this == OVR_GlobalLog)
- {
- // TBD: perhaps we should ASSERT if this happens before system shutdown?
- OVR_GlobalLog = 0;
- }
-}
-
-void Log::LogMessageVarg(LogMessageType messageType, const char* fmt, va_list argList)
-{
- if ((messageType & LoggingMask) == 0)
- return;
-#ifndef OVR_BUILD_DEBUG
- if (IsDebugMessage(messageType))
- return;
-#endif
-
- char buffer[MaxLogBufferMessageSize];
- FormatLog(buffer, MaxLogBufferMessageSize, messageType, fmt, argList);
- DefaultLogOutput(buffer, IsDebugMessage(messageType));
-}
-
-void OVR::Log::LogMessage(LogMessageType messageType, const char* pfmt, ...)
-{
- va_list argList;
- va_start(argList, pfmt);
- LogMessageVarg(messageType, pfmt, argList);
- va_end(argList);
-}
-
-
-void Log::FormatLog(char* buffer, unsigned bufferSize, LogMessageType messageType,
- const char* fmt, va_list argList)
-{
- bool addNewline = true;
-
- switch(messageType)
- {
- case Log_Error: OVR_strcpy(buffer, bufferSize, "Error: "); break;
- case Log_Debug: OVR_strcpy(buffer, bufferSize, "Debug: "); break;
- case Log_Assert: OVR_strcpy(buffer, bufferSize, "Assert: "); break;
- case Log_Text: buffer[0] = 0; addNewline = false; break;
- case Log_DebugText: buffer[0] = 0; addNewline = false; break;
- default:
- buffer[0] = 0;
- addNewline = false;
- break;
- }
-
- UPInt prefixLength = OVR_strlen(buffer);
- char *buffer2 = buffer + prefixLength;
- OVR_vsprintf(buffer2, bufferSize - prefixLength, fmt, argList);
-
- if (addNewline)
- OVR_strcat(buffer, bufferSize, "\n");
-}
-
-
-void Log::DefaultLogOutput(const char* formattedText, bool debug)
-{
-
-#if defined(OVR_OS_WIN32)
- // Under Win32, output regular messages to console if it exists; debug window otherwise.
- static DWORD dummyMode;
- static bool hasConsole = (GetStdHandle(STD_OUTPUT_HANDLE) != INVALID_HANDLE_VALUE) &&
- (GetConsoleMode(GetStdHandle(STD_OUTPUT_HANDLE), &dummyMode));
-
- if (!hasConsole || debug)
- {
- ::OutputDebugStringA(formattedText);
- }
- else
- {
- fputs(formattedText, stdout);
- }
-
-#elif defined(OVR_OS_ANDROID)
- __android_log_write(ANDROID_LOG_INFO, "OVR", formattedText);
-
-#else
- fputs(formattedText, stdout);
-
-#endif
-
- // Just in case.
- OVR_UNUSED2(formattedText, debug);
-}
-
-
-//static
-void Log::SetGlobalLog(Log *log)
-{
- OVR_GlobalLog = log;
-}
-//static
-Log* Log::GetGlobalLog()
-{
-// No global log by default?
-// if (!OVR_GlobalLog)
-// OVR_GlobalLog = GetDefaultLog();
- return OVR_GlobalLog;
-}
-
-//static
-Log* Log::GetDefaultLog()
-{
- // Create default log pointer statically so that it can be used
- // even during startup.
- static Log defaultLog;
- return &defaultLog;
-}
-
-
-//-----------------------------------------------------------------------------------
-// ***** Global Logging functions
-
-#define OVR_LOG_FUNCTION_IMPL(Name) \
- void Log##Name(const char* fmt, ...) \
- { \
- if (OVR_GlobalLog) \
- { \
- va_list argList; va_start(argList, fmt); \
- OVR_GlobalLog->LogMessageVarg(Log_##Name, fmt, argList); \
- va_end(argList); \
- } \
- }
-
-OVR_LOG_FUNCTION_IMPL(Text)
-OVR_LOG_FUNCTION_IMPL(Error)
-
-#ifdef OVR_BUILD_DEBUG
-OVR_LOG_FUNCTION_IMPL(DebugText)
-OVR_LOG_FUNCTION_IMPL(Debug)
-OVR_LOG_FUNCTION_IMPL(Assert)
-#endif
-
-} // OVR
+/************************************************************************************
+
+Filename : OVR_Log.cpp
+Content : Logging support
+Created : September 19, 2012
+Notes :
+
+Copyright : Copyright 2012 Oculus VR, Inc. All Rights reserved.
+
+Use of this software is subject to the terms of the Oculus license
+agreement provided at the time of installation or download, or which
+otherwise accompanies this software in either electronic or hard copy form.
+
+************************************************************************************/
+
+#include "OVR_Log.h"
+#include "OVR_Std.h"
+#include <stdarg.h>
+#include <stdio.h>
+
+#if defined(OVR_OS_WIN32)
+#include <windows.h>
+#elif defined(OVR_OS_ANDROID)
+#include <android/log.h>
+#endif
+
+namespace OVR {
+
+// Global Log pointer.
+Log* volatile OVR_GlobalLog = 0;
+
+//-----------------------------------------------------------------------------------
+// ***** Log Implementation
+
+Log::~Log()
+{
+ // Clear out global log
+ if (this == OVR_GlobalLog)
+ {
+ // TBD: perhaps we should ASSERT if this happens before system shutdown?
+ OVR_GlobalLog = 0;
+ }
+}
+
+void Log::LogMessageVarg(LogMessageType messageType, const char* fmt, va_list argList)
+{
+ if ((messageType & LoggingMask) == 0)
+ return;
+#ifndef OVR_BUILD_DEBUG
+ if (IsDebugMessage(messageType))
+ return;
+#endif
+
+ char buffer[MaxLogBufferMessageSize];
+ FormatLog(buffer, MaxLogBufferMessageSize, messageType, fmt, argList);
+ DefaultLogOutput(buffer, IsDebugMessage(messageType));
+}
+
+void OVR::Log::LogMessage(LogMessageType messageType, const char* pfmt, ...)
+{
+ va_list argList;
+ va_start(argList, pfmt);
+ LogMessageVarg(messageType, pfmt, argList);
+ va_end(argList);
+}
+
+
+void Log::FormatLog(char* buffer, unsigned bufferSize, LogMessageType messageType,
+ const char* fmt, va_list argList)
+{
+ bool addNewline = true;
+
+ switch(messageType)
+ {
+ case Log_Error: OVR_strcpy(buffer, bufferSize, "Error: "); break;
+ case Log_Debug: OVR_strcpy(buffer, bufferSize, "Debug: "); break;
+ case Log_Assert: OVR_strcpy(buffer, bufferSize, "Assert: "); break;
+ case Log_Text: buffer[0] = 0; addNewline = false; break;
+ case Log_DebugText: buffer[0] = 0; addNewline = false; break;
+ default:
+ buffer[0] = 0;
+ addNewline = false;
+ break;
+ }
+
+ UPInt prefixLength = OVR_strlen(buffer);
+ char *buffer2 = buffer + prefixLength;
+ OVR_vsprintf(buffer2, bufferSize - prefixLength, fmt, argList);
+
+ if (addNewline)
+ OVR_strcat(buffer, bufferSize, "\n");
+}
+
+
+void Log::DefaultLogOutput(const char* formattedText, bool debug)
+{
+
+#if defined(OVR_OS_WIN32)
+ // Under Win32, output regular messages to console if it exists; debug window otherwise.
+ static DWORD dummyMode;
+ static bool hasConsole = (GetStdHandle(STD_OUTPUT_HANDLE) != INVALID_HANDLE_VALUE) &&
+ (GetConsoleMode(GetStdHandle(STD_OUTPUT_HANDLE), &dummyMode));
+
+ if (!hasConsole || debug)
+ {
+ ::OutputDebugStringA(formattedText);
+ }
+ else
+ {
+ fputs(formattedText, stdout);
+ }
+
+#elif defined(OVR_OS_ANDROID)
+ __android_log_write(ANDROID_LOG_INFO, "OVR", formattedText);
+
+#else
+ fputs(formattedText, stdout);
+
+#endif
+
+ // Just in case.
+ OVR_UNUSED2(formattedText, debug);
+}
+
+
+//static
+void Log::SetGlobalLog(Log *log)
+{
+ OVR_GlobalLog = log;
+}
+//static
+Log* Log::GetGlobalLog()
+{
+// No global log by default?
+// if (!OVR_GlobalLog)
+// OVR_GlobalLog = GetDefaultLog();
+ return OVR_GlobalLog;
+}
+
+//static
+Log* Log::GetDefaultLog()
+{
+ // Create default log pointer statically so that it can be used
+ // even during startup.
+ static Log defaultLog;
+ return &defaultLog;
+}
+
+
+//-----------------------------------------------------------------------------------
+// ***** Global Logging functions
+
+#define OVR_LOG_FUNCTION_IMPL(Name) \
+ void Log##Name(const char* fmt, ...) \
+ { \
+ if (OVR_GlobalLog) \
+ { \
+ va_list argList; va_start(argList, fmt); \
+ OVR_GlobalLog->LogMessageVarg(Log_##Name, fmt, argList); \
+ va_end(argList); \
+ } \
+ }
+
+OVR_LOG_FUNCTION_IMPL(Text)
+OVR_LOG_FUNCTION_IMPL(Error)
+
+#ifdef OVR_BUILD_DEBUG
+OVR_LOG_FUNCTION_IMPL(DebugText)
+OVR_LOG_FUNCTION_IMPL(Debug)
+OVR_LOG_FUNCTION_IMPL(Assert)
+#endif
+
+} // OVR
diff --git a/LibOVR/Src/Kernel/OVR_Log.h b/LibOVR/Src/Kernel/OVR_Log.h
index acc298d..d49d466 100644
--- a/LibOVR/Src/Kernel/OVR_Log.h
+++ b/LibOVR/Src/Kernel/OVR_Log.h
@@ -1,193 +1,193 @@
-/************************************************************************************
-
-PublicHeader: OVR
-Filename : OVR_Log.h
-Content : Logging support
-Created : September 19, 2012
-Notes :
-
-Copyright : Copyright 2012 Oculus VR, Inc. All Rights reserved.
-
-Use of this software is subject to the terms of the Oculus license
-agreement provided at the time of installation or download, or which
-otherwise accompanies this software in either electronic or hard copy form.
-
-************************************************************************************/
-
-#ifndef OVR_Log_h
-#define OVR_Log_h
-
-#include "OVR_Types.h"
-#include <stdarg.h>
-
-namespace OVR {
-
-//-----------------------------------------------------------------------------------
-// ***** Logging Constants
-
-// LogMaskConstants defined bit mask constants that describe what log messages
-// should be displayed.
-enum LogMaskConstants
-{
- LogMask_Regular = 0x100,
- LogMask_Debug = 0x200,
- LogMask_None = 0,
- LogMask_All = LogMask_Regular|LogMask_Debug
-};
-
-
-// LogMessageType describes the type of the log message, controls when it is
-// displayed and what prefix/suffix is given to it. Messages are subdivided into
-// regular and debug logging types. Debug logging is only generated in debug builds.
-//
-// Log_Text - General output text displayed without prefix or new-line.
-// Used in OVR libraries for general log flow messages
-// such as "Device Initialized".
-//
-// Log_Error - Error message output with "Error: %s\n", intended for
-// application/sample-level use only, in cases where an expected
-// operation failed. OVR libraries should not use this internally,
-// reporting status codes instead.
-//
-// Log_DebugText - Message without prefix or new lines; output in Debug build only.
-//
-// Log_Debug - Debug-build only message, formatted with "Debug: %s\n".
-// Intended to comment on incorrect API usage that doesn't lead
-// to crashes but can be avoided with proper use.
-// There is no Debug Error on purpose, since real errors should
-// be handled by API user.
-//
-// Log_Assert - Debug-build only message, formatted with "Assert: %s\n".
-// Intended for severe unrecoverable conditions in library
-// source code. Generated though OVR_ASSERT_MSG(c, "Text").
-
-enum LogMessageType
-{
- // General Logging
- Log_Text = LogMask_Regular | 0,
- Log_Error = LogMask_Regular | 1, // "Error: %s\n".
-
- // Debug-only messages (not generated in release build)
- Log_DebugText = LogMask_Debug | 0,
- Log_Debug = LogMask_Debug | 1, // "Debug: %s\n".
- Log_Assert = LogMask_Debug | 2, // "Assert: %s\n".
-};
-
-
-// LOG_VAARG_ATTRIBUTE macro, enforces printf-style fromatting for message types
-#ifdef __GNUC__
-# define OVR_LOG_VAARG_ATTRIBUTE(a,b) __attribute__((format (printf, a, b)))
-#else
-# define OVR_LOG_VAARG_ATTRIBUTE(a,b)
-#endif
-
-
-//-----------------------------------------------------------------------------------
-// ***** Log
-
-// Log defines a base class interface that can be implemented to catch both
-// debug and runtime messages.
-// Debug logging can be overridden by calling Log::SetGlobalLog.
-
-class Log
-{
- friend class System;
-public:
- Log(unsigned logMask = LogMask_Debug) : LoggingMask(logMask) { }
- virtual ~Log();
-
- // Log formating buffer size used by default LogMessageVarg. Longer strings are truncated.
- enum { MaxLogBufferMessageSize = 2048 };
-
- unsigned GetLoggingMask() const { return LoggingMask; }
- void SetLoggingMask(unsigned logMask) { LoggingMask = logMask; }
-
- // This virtual function receives all the messages,
- // developers should override this function in order to do custom logging
- virtual void LogMessageVarg(LogMessageType messageType, const char* fmt, va_list argList);
-
- // Call the logging function with specific message type, with no type filtering.
- void LogMessage(LogMessageType messageType,
- const char* fmt, ...) OVR_LOG_VAARG_ATTRIBUTE(3,4);
-
-
- // Helper used by LogMessageVarg to format the log message, writing the resulting
- // string into buffer. It formats text based on fmt and appends prefix/new line
- // based on LogMessageType.
- static void FormatLog(char* buffer, unsigned bufferSize, LogMessageType messageType,
- const char* fmt, va_list argList);
-
- // Default log output implementation used by by LogMessageVarg.
- // Debug flag may be used to re-direct output on some platforms, but doesn't
- // necessarily disable it in release builds; that is the job of the called.
- static void DefaultLogOutput(const char* textBuffer, bool debug);
-
- // Determines if the specified message type is for debugging only.
- static bool IsDebugMessage(LogMessageType messageType)
- {
- return (messageType & LogMask_Debug) != 0;
- }
-
- // *** Global APIs
-
- // Global Log registration APIs.
- // - Global log is used for OVR_DEBUG messages. Set global log to null (0)
- // to disable all logging.
- static void SetGlobalLog(Log *log);
- static Log* GetGlobalLog();
-
- // Returns default log singleton instance.
- static Log* GetDefaultLog();
-
- // Applies logMask to the default log and returns a pointer to it.
- // By default, only Debug logging is enabled, so to avoid SDK generating console
- // messages in user app (those are always disabled in release build,
- // even if the flag is set). This function is useful in System constructor.
- static Log* ConfigureDefaultLog(unsigned logMask = LogMask_Debug)
- {
- Log* log = GetDefaultLog();
- log->SetLoggingMask(logMask);
- return log;
- }
-
-private:
- // Logging mask described by LogMaskConstants.
- unsigned LoggingMask;
-};
-
-
-//-----------------------------------------------------------------------------------
-// ***** Global Logging Functions and Debug Macros
-
-// These functions will output text to global log with semantics described by
-// their LogMessageType.
-void LogText(const char* fmt, ...) OVR_LOG_VAARG_ATTRIBUTE(1,2);
-void LogError(const char* fmt, ...) OVR_LOG_VAARG_ATTRIBUTE(1,2);
-
-#ifdef OVR_BUILD_DEBUG
-
- // Debug build only logging.
- void LogDebugText(const char* fmt, ...) OVR_LOG_VAARG_ATTRIBUTE(1,2);
- void LogDebug(const char* fmt, ...) OVR_LOG_VAARG_ATTRIBUTE(1,2);
- void LogAssert(const char* fmt, ...) OVR_LOG_VAARG_ATTRIBUTE(1,2);
-
- // Macro to do debug logging, printf-style.
- // An extra set of set of parenthesis must be used around arguments,
- // as in: OVR_LOG_DEBUG(("Value %d", 2)).
- #define OVR_DEBUG_LOG(args) do { OVR::LogDebug args; } while(0)
- #define OVR_DEBUG_LOG_TEXT(args) do { OVR::LogDebugText args; } while(0)
-
- #define OVR_ASSERT_LOG(c, args) do { if (!(c)) { OVR::LogAssert args; OVR_DEBUG_BREAK; } } while(0)
-
-#else
-
- // If not in debug build, macros do nothing.
- #define OVR_DEBUG_LOG(args) ((void)0)
- #define OVR_DEBUG_LOG_TEXT(args) ((void)0)
- #define OVR_ASSERT_LOG(c, args) ((void)0)
-
-#endif
-
-} // OVR
-
-#endif
+/************************************************************************************
+
+PublicHeader: OVR
+Filename : OVR_Log.h
+Content : Logging support
+Created : September 19, 2012
+Notes :
+
+Copyright : Copyright 2012 Oculus VR, Inc. All Rights reserved.
+
+Use of this software is subject to the terms of the Oculus license
+agreement provided at the time of installation or download, or which
+otherwise accompanies this software in either electronic or hard copy form.
+
+************************************************************************************/
+
+#ifndef OVR_Log_h
+#define OVR_Log_h
+
+#include "OVR_Types.h"
+#include <stdarg.h>
+
+namespace OVR {
+
+//-----------------------------------------------------------------------------------
+// ***** Logging Constants
+
+// LogMaskConstants defined bit mask constants that describe what log messages
+// should be displayed.
+enum LogMaskConstants
+{
+ LogMask_Regular = 0x100,
+ LogMask_Debug = 0x200,
+ LogMask_None = 0,
+ LogMask_All = LogMask_Regular|LogMask_Debug
+};
+
+
+// LogMessageType describes the type of the log message, controls when it is
+// displayed and what prefix/suffix is given to it. Messages are subdivided into
+// regular and debug logging types. Debug logging is only generated in debug builds.
+//
+// Log_Text - General output text displayed without prefix or new-line.
+// Used in OVR libraries for general log flow messages
+// such as "Device Initialized".
+//
+// Log_Error - Error message output with "Error: %s\n", intended for
+// application/sample-level use only, in cases where an expected
+// operation failed. OVR libraries should not use this internally,
+// reporting status codes instead.
+//
+// Log_DebugText - Message without prefix or new lines; output in Debug build only.
+//
+// Log_Debug - Debug-build only message, formatted with "Debug: %s\n".
+// Intended to comment on incorrect API usage that doesn't lead
+// to crashes but can be avoided with proper use.
+// There is no Debug Error on purpose, since real errors should
+// be handled by API user.
+//
+// Log_Assert - Debug-build only message, formatted with "Assert: %s\n".
+// Intended for severe unrecoverable conditions in library
+// source code. Generated though OVR_ASSERT_MSG(c, "Text").
+
+enum LogMessageType
+{
+ // General Logging
+ Log_Text = LogMask_Regular | 0,
+ Log_Error = LogMask_Regular | 1, // "Error: %s\n".
+
+ // Debug-only messages (not generated in release build)
+ Log_DebugText = LogMask_Debug | 0,
+ Log_Debug = LogMask_Debug | 1, // "Debug: %s\n".
+ Log_Assert = LogMask_Debug | 2, // "Assert: %s\n".
+};
+
+
+// LOG_VAARG_ATTRIBUTE macro, enforces printf-style fromatting for message types
+#ifdef __GNUC__
+# define OVR_LOG_VAARG_ATTRIBUTE(a,b) __attribute__((format (printf, a, b)))
+#else
+# define OVR_LOG_VAARG_ATTRIBUTE(a,b)
+#endif
+
+
+//-----------------------------------------------------------------------------------
+// ***** Log
+
+// Log defines a base class interface that can be implemented to catch both
+// debug and runtime messages.
+// Debug logging can be overridden by calling Log::SetGlobalLog.
+
+class Log
+{
+ friend class System;
+public:
+ Log(unsigned logMask = LogMask_Debug) : LoggingMask(logMask) { }
+ virtual ~Log();
+
+ // Log formating buffer size used by default LogMessageVarg. Longer strings are truncated.
+ enum { MaxLogBufferMessageSize = 2048 };
+
+ unsigned GetLoggingMask() const { return LoggingMask; }
+ void SetLoggingMask(unsigned logMask) { LoggingMask = logMask; }
+
+ // This virtual function receives all the messages,
+ // developers should override this function in order to do custom logging
+ virtual void LogMessageVarg(LogMessageType messageType, const char* fmt, va_list argList);
+
+ // Call the logging function with specific message type, with no type filtering.
+ void LogMessage(LogMessageType messageType,
+ const char* fmt, ...) OVR_LOG_VAARG_ATTRIBUTE(3,4);
+
+
+ // Helper used by LogMessageVarg to format the log message, writing the resulting
+ // string into buffer. It formats text based on fmt and appends prefix/new line
+ // based on LogMessageType.
+ static void FormatLog(char* buffer, unsigned bufferSize, LogMessageType messageType,
+ const char* fmt, va_list argList);
+
+ // Default log output implementation used by by LogMessageVarg.
+ // Debug flag may be used to re-direct output on some platforms, but doesn't
+ // necessarily disable it in release builds; that is the job of the called.
+ static void DefaultLogOutput(const char* textBuffer, bool debug);
+
+ // Determines if the specified message type is for debugging only.
+ static bool IsDebugMessage(LogMessageType messageType)
+ {
+ return (messageType & LogMask_Debug) != 0;
+ }
+
+ // *** Global APIs
+
+ // Global Log registration APIs.
+ // - Global log is used for OVR_DEBUG messages. Set global log to null (0)
+ // to disable all logging.
+ static void SetGlobalLog(Log *log);
+ static Log* GetGlobalLog();
+
+ // Returns default log singleton instance.
+ static Log* GetDefaultLog();
+
+ // Applies logMask to the default log and returns a pointer to it.
+ // By default, only Debug logging is enabled, so to avoid SDK generating console
+ // messages in user app (those are always disabled in release build,
+ // even if the flag is set). This function is useful in System constructor.
+ static Log* ConfigureDefaultLog(unsigned logMask = LogMask_Debug)
+ {
+ Log* log = GetDefaultLog();
+ log->SetLoggingMask(logMask);
+ return log;
+ }
+
+private:
+ // Logging mask described by LogMaskConstants.
+ unsigned LoggingMask;
+};
+
+
+//-----------------------------------------------------------------------------------
+// ***** Global Logging Functions and Debug Macros
+
+// These functions will output text to global log with semantics described by
+// their LogMessageType.
+void LogText(const char* fmt, ...) OVR_LOG_VAARG_ATTRIBUTE(1,2);
+void LogError(const char* fmt, ...) OVR_LOG_VAARG_ATTRIBUTE(1,2);
+
+#ifdef OVR_BUILD_DEBUG
+
+ // Debug build only logging.
+ void LogDebugText(const char* fmt, ...) OVR_LOG_VAARG_ATTRIBUTE(1,2);
+ void LogDebug(const char* fmt, ...) OVR_LOG_VAARG_ATTRIBUTE(1,2);
+ void LogAssert(const char* fmt, ...) OVR_LOG_VAARG_ATTRIBUTE(1,2);
+
+ // Macro to do debug logging, printf-style.
+ // An extra set of set of parenthesis must be used around arguments,
+ // as in: OVR_LOG_DEBUG(("Value %d", 2)).
+ #define OVR_DEBUG_LOG(args) do { OVR::LogDebug args; } while(0)
+ #define OVR_DEBUG_LOG_TEXT(args) do { OVR::LogDebugText args; } while(0)
+
+ #define OVR_ASSERT_LOG(c, args) do { if (!(c)) { OVR::LogAssert args; OVR_DEBUG_BREAK; } } while(0)
+
+#else
+
+ // If not in debug build, macros do nothing.
+ #define OVR_DEBUG_LOG(args) ((void)0)
+ #define OVR_DEBUG_LOG_TEXT(args) ((void)0)
+ #define OVR_ASSERT_LOG(c, args) ((void)0)
+
+#endif
+
+} // OVR
+
+#endif
diff --git a/LibOVR/Src/Kernel/OVR_Math.cpp b/LibOVR/Src/Kernel/OVR_Math.cpp
index eaf23fe..3c35bde 100644
--- a/LibOVR/Src/Kernel/OVR_Math.cpp
+++ b/LibOVR/Src/Kernel/OVR_Math.cpp
@@ -1,153 +1,153 @@
-/************************************************************************************
-
-Filename : OVR_Math.h
-Content : Implementation of 3D primitives such as vectors, matrices.
-Created : September 4, 2012
-Authors : Andrew Reisse, Michael Antonov
-
-Copyright : Copyright 2012 Oculus VR, Inc. All Rights reserved.
-
-Use of this software is subject to the terms of the Oculus license
-agreement provided at the time of installation or download, or which
-otherwise accompanies this software in either electronic or hard copy form.
-
-*************************************************************************************/
-
-#include "OVR_Math.h"
-
-#include <float.h>
-
-namespace OVR {
-
-
-//-------------------------------------------------------------------------------------
-// ***** Math
-
-
-// Single-precision Math constants class.
-const float Math<float>::Pi = 3.1415926f;
-const float Math<float>::TwoPi = 3.1415926f * 2;
-const float Math<float>::PiOver2 = 3.1415926f / 2.0f;
-const float Math<float>::PiOver4 = 3.1415926f / 4.0f;
-const float Math<float>::E = 2.7182818f;
-
-const float Math<float>::MaxValue = FLT_MAX;
-const float Math<float>::MinPositiveValue = FLT_MIN;
-
-const float Math<float>::RadToDegreeFactor = 360.0f / Math<float>::TwoPi;
-const float Math<float>::DegreeToRadFactor = Math<float>::TwoPi / 360.0f;
-
-const float Math<float>::Tolerance = 0.00001f;
-const float Math<float>::SingularityRadius = 0.0000001f; // Use for Gimbal lock numerical problems
-
-
-// Double-precision Math constants class.
-const double Math<double>::Pi = 3.14159265358979;
-const double Math<double>::TwoPi = 3.14159265358979 * 2;
-const double Math<double>::PiOver2 = 3.14159265358979 / 2.0;
-const double Math<double>::PiOver4 = 3.14159265358979 / 4.0;
-const double Math<double>::E = 2.71828182845905;
-
-const double Math<double>::MaxValue = DBL_MAX;
-const double Math<double>::MinPositiveValue = DBL_MIN;
-
-const double Math<double>::RadToDegreeFactor = 360.0 / Math<double>::TwoPi;
-const double Math<double>::DegreeToRadFactor = Math<double>::TwoPi / 360.0;
-
-const double Math<double>::Tolerance = 0.00001;
-const double Math<double>::SingularityRadius = 0.000000000001; // Use for Gimbal lock numerical problems
-
-
-
-//-------------------------------------------------------------------------------------
-// ***** Matrix4f
-
-
-Matrix4f Matrix4f::LookAtRH(const Vector3f& eye, const Vector3f& at, const Vector3f& up)
-{
- Vector3f z = (eye - at).Normalized(); // Forward
- Vector3f x = up.Cross(z).Normalized(); // Right
- Vector3f y = z.Cross(x);
-
- Matrix4f m(x.x, x.y, x.z, -(x * eye),
- y.x, y.y, y.z, -(y * eye),
- z.x, z.y, z.z, -(z * eye),
- 0, 0, 0, 1 );
- return m;
-}
-
-Matrix4f Matrix4f::LookAtLH(const Vector3f& eye, const Vector3f& at, const Vector3f& up)
-{
- Vector3f z = (at - eye).Normalized(); // Forward
- Vector3f x = up.Cross(z).Normalized(); // Right
- Vector3f y = z.Cross(x);
-
- Matrix4f m(x.x, x.y, x.z, -(x * eye),
- y.x, y.y, y.z, -(y * eye),
- z.x, z.y, z.z, -(z * eye),
- 0, 0, 0, 1 );
- return m;
-}
-
-
-Matrix4f Matrix4f::PerspectiveLH(float yfov, float aspect, float znear, float zfar)
-{
- Matrix4f m;
- float tanHalfFov = tan(yfov * 0.5f);
-
- m.M[0][0] = 1.0f / (aspect * tanHalfFov);
- m.M[1][1] = 1.0f / tanHalfFov;
- m.M[2][2] = zfar / (zfar - znear);
- m.M[3][2] = 1.0f;
- m.M[2][3] = (zfar * znear) / (znear - zfar);
- m.M[3][3] = 0.0f;
-
- // Note: Post-projection matrix result assumes Left-Handed coordinate system,
- // with Y up, X right and Z forward. This supports positive z-buffer values.
- return m;
-}
-
-
-Matrix4f Matrix4f::PerspectiveRH(float yfov, float aspect, float znear, float zfar)
-{
- Matrix4f m;
- float tanHalfFov = tan(yfov * 0.5f);
-
- m.M[0][0] = 1.0f / (aspect * tanHalfFov);
- m.M[1][1] = 1.0f / tanHalfFov;
- m.M[2][2] = zfar / (znear - zfar);
- // m.M[2][2] = zfar / (zfar - znear);
- m.M[3][2] = -1.0f;
- m.M[2][3] = (zfar * znear) / (znear - zfar);
- m.M[3][3] = 0.0f;
-
- // Note: Post-projection matrix result assumes Left-Handed coordinate system,
- // with Y up, X right and Z forward. This supports positive z-buffer values.
- // This is the case even for RHS cooridnate input.
- return m;
-}
-
-
-/*
-OffCenterLH
-
-2*zn/(r-l) 0 0 0
-0 2*zn/(t-b) 0 0
-(l+r)/(l-r) (t+b)/(b-t) zf/(zf-zn) 1
-0 0 zn*zf/(zn-zf) 0
-
-*/
-
-
-Matrix4f Matrix4f::Ortho2D(float w, float h)
-{
- Matrix4f m;
- m.M[0][0] = 2.0f/w;
- m.M[1][1] = -2.0f/h;
- m.M[0][3] = -1.0;
- m.M[1][3] = 1.0;
- m.M[2][2] = 0;
- return m;
-}
-
-}
+/************************************************************************************
+
+Filename : OVR_Math.h
+Content : Implementation of 3D primitives such as vectors, matrices.
+Created : September 4, 2012
+Authors : Andrew Reisse, Michael Antonov
+
+Copyright : Copyright 2012 Oculus VR, Inc. All Rights reserved.
+
+Use of this software is subject to the terms of the Oculus license
+agreement provided at the time of installation or download, or which
+otherwise accompanies this software in either electronic or hard copy form.
+
+*************************************************************************************/
+
+#include "OVR_Math.h"
+
+#include <float.h>
+
+namespace OVR {
+
+
+//-------------------------------------------------------------------------------------
+// ***** Math
+
+
+// Single-precision Math constants class.
+const float Math<float>::Pi = 3.1415926f;
+const float Math<float>::TwoPi = 3.1415926f * 2;
+const float Math<float>::PiOver2 = 3.1415926f / 2.0f;
+const float Math<float>::PiOver4 = 3.1415926f / 4.0f;
+const float Math<float>::E = 2.7182818f;
+
+const float Math<float>::MaxValue = FLT_MAX;
+const float Math<float>::MinPositiveValue = FLT_MIN;
+
+const float Math<float>::RadToDegreeFactor = 360.0f / Math<float>::TwoPi;
+const float Math<float>::DegreeToRadFactor = Math<float>::TwoPi / 360.0f;
+
+const float Math<float>::Tolerance = 0.00001f;
+const float Math<float>::SingularityRadius = 0.0000001f; // Use for Gimbal lock numerical problems
+
+
+// Double-precision Math constants class.
+const double Math<double>::Pi = 3.14159265358979;
+const double Math<double>::TwoPi = 3.14159265358979 * 2;
+const double Math<double>::PiOver2 = 3.14159265358979 / 2.0;
+const double Math<double>::PiOver4 = 3.14159265358979 / 4.0;
+const double Math<double>::E = 2.71828182845905;
+
+const double Math<double>::MaxValue = DBL_MAX;
+const double Math<double>::MinPositiveValue = DBL_MIN;
+
+const double Math<double>::RadToDegreeFactor = 360.0 / Math<double>::TwoPi;
+const double Math<double>::DegreeToRadFactor = Math<double>::TwoPi / 360.0;
+
+const double Math<double>::Tolerance = 0.00001;
+const double Math<double>::SingularityRadius = 0.000000000001; // Use for Gimbal lock numerical problems
+
+
+
+//-------------------------------------------------------------------------------------
+// ***** Matrix4f
+
+
+Matrix4f Matrix4f::LookAtRH(const Vector3f& eye, const Vector3f& at, const Vector3f& up)
+{
+ Vector3f z = (eye - at).Normalized(); // Forward
+ Vector3f x = up.Cross(z).Normalized(); // Right
+ Vector3f y = z.Cross(x);
+
+ Matrix4f m(x.x, x.y, x.z, -(x * eye),
+ y.x, y.y, y.z, -(y * eye),
+ z.x, z.y, z.z, -(z * eye),
+ 0, 0, 0, 1 );
+ return m;
+}
+
+Matrix4f Matrix4f::LookAtLH(const Vector3f& eye, const Vector3f& at, const Vector3f& up)
+{
+ Vector3f z = (at - eye).Normalized(); // Forward
+ Vector3f x = up.Cross(z).Normalized(); // Right
+ Vector3f y = z.Cross(x);
+
+ Matrix4f m(x.x, x.y, x.z, -(x * eye),
+ y.x, y.y, y.z, -(y * eye),
+ z.x, z.y, z.z, -(z * eye),
+ 0, 0, 0, 1 );
+ return m;
+}
+
+
+Matrix4f Matrix4f::PerspectiveLH(float yfov, float aspect, float znear, float zfar)
+{
+ Matrix4f m;
+ float tanHalfFov = tan(yfov * 0.5f);
+
+ m.M[0][0] = 1.0f / (aspect * tanHalfFov);
+ m.M[1][1] = 1.0f / tanHalfFov;
+ m.M[2][2] = zfar / (zfar - znear);
+ m.M[3][2] = 1.0f;
+ m.M[2][3] = (zfar * znear) / (znear - zfar);
+ m.M[3][3] = 0.0f;
+
+ // Note: Post-projection matrix result assumes Left-Handed coordinate system,
+ // with Y up, X right and Z forward. This supports positive z-buffer values.
+ return m;
+}
+
+
+Matrix4f Matrix4f::PerspectiveRH(float yfov, float aspect, float znear, float zfar)
+{
+ Matrix4f m;
+ float tanHalfFov = tan(yfov * 0.5f);
+
+ m.M[0][0] = 1.0f / (aspect * tanHalfFov);
+ m.M[1][1] = 1.0f / tanHalfFov;
+ m.M[2][2] = zfar / (znear - zfar);
+ // m.M[2][2] = zfar / (zfar - znear);
+ m.M[3][2] = -1.0f;
+ m.M[2][3] = (zfar * znear) / (znear - zfar);
+ m.M[3][3] = 0.0f;
+
+ // Note: Post-projection matrix result assumes Left-Handed coordinate system,
+ // with Y up, X right and Z forward. This supports positive z-buffer values.
+ // This is the case even for RHS cooridnate input.
+ return m;
+}
+
+
+/*
+OffCenterLH
+
+2*zn/(r-l) 0 0 0
+0 2*zn/(t-b) 0 0
+(l+r)/(l-r) (t+b)/(b-t) zf/(zf-zn) 1
+0 0 zn*zf/(zn-zf) 0
+
+*/
+
+
+Matrix4f Matrix4f::Ortho2D(float w, float h)
+{
+ Matrix4f m;
+ m.M[0][0] = 2.0f/w;
+ m.M[1][1] = -2.0f/h;
+ m.M[0][3] = -1.0;
+ m.M[1][3] = 1.0;
+ m.M[2][2] = 0;
+ return m;
+}
+
+}
diff --git a/LibOVR/Src/Kernel/OVR_Math.h b/LibOVR/Src/Kernel/OVR_Math.h
index 8c5a7ba..2b255c7 100644
--- a/LibOVR/Src/Kernel/OVR_Math.h
+++ b/LibOVR/Src/Kernel/OVR_Math.h
@@ -1,1070 +1,1149 @@
-/************************************************************************************
-
-PublicHeader: OVR.h
-Filename : OVR_Math.h
-Content : Implementation of 3D primitives such as vectors, matrices.
-Created : September 4, 2012
-Authors : Andrew Reisse, Michael Antonov, Steve LaValle, Anna Yershova
-
-Copyright : Copyright 2012 Oculus VR, Inc. All Rights reserved.
-
-Use of this software is subject to the terms of the Oculus license
-agreement provided at the time of installation or download, or which
-otherwise accompanies this software in either electronic or hard copy form.
-
-*************************************************************************************/
-
-#ifndef OVR_Math_h
-#define OVR_Math_h
-
-#include <assert.h>
-#include <stdlib.h>
-#include <math.h>
-
-#include "OVR_Types.h"
-#include "OVR_RefCount.h"
-
-namespace OVR {
-
-//-------------------------------------------------------------------------------------
-// Constants for 3D world/axis definitions.
-
-// Definitions of axes for coordinate and rotation conversions.
-enum Axis
-{
- Axis_X = 0, Axis_Y = 1, Axis_Z = 2
-};
-
-// RotateDirection describes the rotation direction around an axis, interpreted as follows:
-// CW - Clockwise while looking "down" from positive axis towards the origin.
-// CCW - Counter-clockwise while looking from the positive axis towards the origin,
-// which is in the negative axis direction.
-// CCW is the default for the RHS coordinate system. Oculus standard RHS coordinate
-// system defines Y up, X right, and Z back (pointing out from the screen). In this
-// system Rotate_CCW around Z will specifies counter-clockwise rotation in XY plane.
-enum RotateDirection
-{
- Rotate_CCW = 1,
- Rotate_CW = -1
-};
-
-enum HandedSystem
-{
- Handed_R = 1, Handed_L = -1
-};
-
-// AxisDirection describes which way the axis points. Used by WorldAxes.
-enum AxisDirection
-{
- Axis_Up = 2,
- Axis_Down = -2,
- Axis_Right = 1,
- Axis_Left = -1,
- Axis_In = 3,
- Axis_Out = -3
-};
-
-struct WorldAxes
-{
- AxisDirection XAxis, YAxis, ZAxis;
-
- WorldAxes(AxisDirection x, AxisDirection y, AxisDirection z)
- : XAxis(x), YAxis(y), ZAxis(z)
- { OVR_ASSERT(abs(x) != abs(y) && abs(y) != abs(z) && abs(z) != abs(x));}
-};
-
-
-//-------------------------------------------------------------------------------------
-// ***** Math
-
-// Math class contains constants and functions. This class is a template specialized
-// per type, with Math<float> and Math<double> being distinct.
-template<class Type>
-class Math
-{
-};
-
-// Single-precision Math constants class.
-template<>
-class Math<float>
-{
-public:
- static const float Pi;
- static const float TwoPi;
- static const float PiOver2;
- static const float PiOver4;
- static const float E;
-
- static const float MaxValue; // Largest positive float Value
- static const float MinPositiveValue; // Smallest possible positive value
-
- static const float RadToDegreeFactor;
- static const float DegreeToRadFactor;
-
- static const float Tolerance; // 0.00001f;
- static const float SingularityRadius; //0.00000000001f for Gimbal lock numerical problems
-};
-
-// Double-precision Math constants class.
-template<>
-class Math<double>
-{
-public:
- static const double Pi;
- static const double TwoPi;
- static const double PiOver2;
- static const double PiOver4;
- static const double E;
-
- static const double MaxValue; // Largest positive double Value
- static const double MinPositiveValue; // Smallest possible positive value
-
- static const double RadToDegreeFactor;
- static const double DegreeToRadFactor;
-
- static const double Tolerance; // 0.00001f;
- static const double SingularityRadius; //0.00000000001 for Gimbal lock numerical problems
-};
-
-typedef Math<float> Mathf;
-typedef Math<double> Mathd;
-
-// Conversion functions between degrees and radians
-template<class FT>
-FT RadToDegree(FT rads) { return rads * Math<FT>::RadToDegreeFactor; }
-template<class FT>
-FT DegreeToRad(FT rads) { return rads * Math<FT>::DegreeToRadFactor; }
-
-template<class T>
-class Quat;
-
-//-------------------------------------------------------------------------------------
-// ***** Vector2f - 2D Vector2f
-
-// Vector2f represents a 2-dimensional vector or point in space,
-// consisting of coordinates x and y,
-
-template<class T>
-class Vector2
-{
-public:
- T x, y;
-
- Vector2() : x(0), y(0) { }
- Vector2(T x_, T y_) : x(x_), y(y_) { }
- explicit Vector2(T s) : x(s), y(s) { }
-
- bool operator== (const Vector2& b) const { return x == b.x && y == b.y; }
- bool operator!= (const Vector2& b) const { return x != b.x || y != b.y; }
-
- Vector2 operator+ (const Vector2& b) const { return Vector2(x + b.x, y + b.y); }
- Vector2& operator+= (const Vector2& b) { x += b.x; y += b.y; return *this; }
- Vector2 operator- (const Vector2& b) const { return Vector2(x - b.x, y - b.y); }
- Vector2& operator-= (const Vector2& b) { x -= b.x; y -= b.y; return *this; }
- Vector2 operator- () const { return Vector2(-x, -y); }
-
- // Scalar multiplication/division scales vector.
- Vector2 operator* (T s) const { return Vector2(x*s, y*s); }
- Vector2& operator*= (T s) { x *= s; y *= s; return *this; }
-
- Vector2 operator/ (T s) const { T rcp = T(1)/s;
- return Vector2(x*rcp, y*rcp); }
- Vector2& operator/= (T s) { T rcp = T(1)/s;
- x *= rcp; y *= rcp;
- return *this; }
-
- // Compare two vectors for equality with tolerance. Returns true if vectors match withing tolerance.
- bool Compare(const Vector2&b, T tolerance = Mathf::Tolerance)
- {
- return (fabs(b.x-x) < tolerance) && (fabs(b.y-y) < tolerance);
- }
-
- // Dot product overload.
- // Used to calculate angle q between two vectors among other things,
- // as (A dot B) = |a||b|cos(q).
- T operator* (const Vector2& b) const { return x*b.x + y*b.y; }
-
- // Returns the angle from this vector to b, in radians.
- T Angle(const Vector2& b) const { return acos((*this * b)/(Length()*b.Length())); }
-
- // Return Length of the vector squared.
- T LengthSq() const { return (x * x + y * y); }
- // Return vector length.
- T Length() const { return sqrt(LengthSq()); }
-
- // Returns distance between two points represented by vectors.
- T Distance(Vector2& b) const { return (*this - b).Length(); }
-
- // Determine if this a unit vector.
- bool IsNormalized() const { return fabs(LengthSq() - T(1)) < Math<T>::Tolerance; }
- // Normalize, convention vector length to 1.
- void Normalize() { *this /= Length(); }
- // Returns normalized (unit) version of the vector without modifying itself.
- Vector2 Normalized() const { return *this / Length(); }
-
- // Linearly interpolates from this vector to another.
- // Factor should be between 0.0 and 1.0, with 0 giving full value to this.
- Vector2 Lerp(const Vector2& b, T f) const { return *this*(T(1) - f) + b*f; }
-
- // Projects this vector onto the argument; in other words,
- // A.Project(B) returns projection of vector A onto B.
- Vector2 ProjectTo(const Vector2& b) const { return b * ((*this * b) / b.LengthSq()); }
-};
-
-
-typedef Vector2<float> Vector2f;
-typedef Vector2<double> Vector2d;
-
-//-------------------------------------------------------------------------------------
-// ***** Vector3f - 3D Vector3f
-
-// Vector3f represents a 3-dimensional vector or point in space,
-// consisting of coordinates x, y and z.
-
-template<class T>
-class Vector3
-{
-public:
- T x, y, z;
-
- Vector3() : x(0), y(0), z(0) { }
- Vector3(T x_, T y_, T z_ = 0) : x(x_), y(y_), z(z_) { }
- explicit Vector3(T s) : x(s), y(s), z(s) { }
-
- bool operator== (const Vector3& b) const { return x == b.x && y == b.y && z == b.z; }
- bool operator!= (const Vector3& b) const { return x != b.x || y != b.y || z != b.z; }
-
- Vector3 operator+ (const Vector3& b) const { return Vector3(x + b.x, y + b.y, z + b.z); }
- Vector3& operator+= (const Vector3& b) { x += b.x; y += b.y; z += b.z; return *this; }
- Vector3 operator- (const Vector3& b) const { return Vector3(x - b.x, y - b.y, z - b.z); }
- Vector3& operator-= (const Vector3& b) { x -= b.x; y -= b.y; z -= b.z; return *this; }
- Vector3 operator- () const { return Vector3(-x, -y, -z); }
-
- // Scalar multiplication/division scales vector.
- Vector3 operator* (T s) const { return Vector3(x*s, y*s, z*s); }
- Vector3& operator*= (T s) { x *= s; y *= s; z *= s; return *this; }
-
- Vector3 operator/ (T s) const { T rcp = T(1)/s;
- return Vector3(x*rcp, y*rcp, z*rcp); }
- Vector3& operator/= (T s) { T rcp = T(1)/s;
- x *= rcp; y *= rcp; z *= rcp;
- return *this; }
-
- // Compare two vectors for equality with tolerance. Returns true if vectors match withing tolerance.
- bool Compare(const Vector3&b, T tolerance = Mathf::Tolerance)
- {
- return (fabs(b.x-x) < tolerance) && (fabs(b.y-y) < tolerance) && (fabs(b.z-z) < tolerance);
- }
-
- // Dot product overload.
- // Used to calculate angle q between two vectors among other things,
- // as (A dot B) = |a||b|cos(q).
- T operator* (const Vector3& b) const { return x*b.x + y*b.y + z*b.z; }
-
- // Compute cross product, which generates a normal vector.
- // Direction vector can be determined by right-hand rule: Pointing index finder in
- // direction a and middle finger in direction b, thumb will point in a.Cross(b).
- Vector3 Cross(const Vector3& b) const { return Vector3(y*b.z - z*b.y,
- z*b.x - x*b.z,
- x*b.y - y*b.x); }
-
- // Returns the angle from this vector to b, in radians.
- T Angle(const Vector3& b) const { return acos((*this * b)/(Length()*b.Length())); }
-
- // Return Length of the vector squared.
- T LengthSq() const { return (x * x + y * y + z * z); }
- // Return vector length.
- T Length() const { return sqrt(LengthSq()); }
-
- // Returns distance between two points represented by vectors.
- T Distance(Vector3& b) const { return (*this - b).Length(); }
-
- // Determine if this a unit vector.
- bool IsNormalized() const { return fabs(LengthSq() - T(1)) < Math<T>::Tolerance; }
- // Normalize, convention vector length to 1.
- void Normalize() { *this /= Length(); }
- // Returns normalized (unit) version of the vector without modifying itself.
- Vector3 Normalized() const { return *this / Length(); }
-
- // Linearly interpolates from this vector to another.
- // Factor should be between 0.0 and 1.0, with 0 giving full value to this.
- Vector3 Lerp(const Vector3& b, T f) const { return *this*(T(1) - f) + b*f; }
-
- // Projects this vector onto the argument; in other words,
- // A.Project(B) returns projection of vector A onto B.
- Vector3 ProjectTo(const Vector3& b) const { return b * ((*this * b) / b.LengthSq()); }
-};
-
-
-typedef Vector3<float> Vector3f;
-typedef Vector3<double> Vector3d;
-
-
-//-------------------------------------------------------------------------------------
-// ***** Matrix4f
-
-// Matrix4f is a 4x4 matrix used for 3d transformations and projections.
-// Translation stored in the last column.
-// The matrix is stored in row-major order in memory, meaning that values
-// of the first row are stored before the next one.
-//
-// The arrangement of the matrix is chosen to be in Right-Handed
-// coordinate system and counterclockwise rotations when looking down
-// the axis
-//
-// Transformation Order:
-// - Transformations are applied from right to left, so the expression
-// M1 * M2 * M3 * V means that the vector V is transformed by M3 first,
-// followed by M2 and M1.
-//
-// Coordinate system: Right Handed
-//
-// Rotations: Counterclockwise when looking down the axis. All angles are in radians.
-//
-// | sx 01 02 tx | // First column (sx, 10, 20): Axis X basis vector.
-// | 10 sy 12 ty | // Second column (01, sy, 21): Axis Y basis vector.
-// | 20 21 sz tz | // Third columnt (02, 12, sz): Axis Z basis vector.
-// | 30 31 32 33 |
-//
-// The basis vectors are first three columns.
-
-class Matrix4f
-{
- static Matrix4f IdentityValue;
-
-public:
- float M[4][4];
-
- enum NoInitType { NoInit };
-
- // Construct with no memory initialization.
- Matrix4f(NoInitType) { }
-
- // By default, we construct identity matrix.
- Matrix4f()
- {
- SetIdentity();
- }
-
- Matrix4f(float m11, float m12, float m13, float m14,
- float m21, float m22, float m23, float m24,
- float m31, float m32, float m33, float m34,
- float m41, float m42, float m43, float m44)
- {
- M[0][0] = m11; M[0][1] = m12; M[0][2] = m13; M[0][3] = m14;
- M[1][0] = m21; M[1][1] = m22; M[1][2] = m23; M[1][3] = m24;
- M[2][0] = m31; M[2][1] = m32; M[2][2] = m33; M[2][3] = m34;
- M[3][0] = m41; M[3][1] = m42; M[3][2] = m43; M[3][3] = m44;
- }
-
- Matrix4f(float m11, float m12, float m13,
- float m21, float m22, float m23,
- float m31, float m32, float m33)
- {
- M[0][0] = m11; M[0][1] = m12; M[0][2] = m13; M[0][3] = 0;
- M[1][0] = m21; M[1][1] = m22; M[1][2] = m23; M[1][3] = 0;
- M[2][0] = m31; M[2][1] = m32; M[2][2] = m33; M[2][3] = 0;
- M[3][0] = 0; M[3][1] = 0; M[3][2] = 0; M[3][3] = 1;
- }
-
- static const Matrix4f& Identity() { return IdentityValue; }
-
- void SetIdentity()
- {
- M[0][0] = M[1][1] = M[2][2] = M[3][3] = 1;
- M[0][1] = M[1][0] = M[2][3] = M[3][1] = 0;
- M[0][2] = M[1][2] = M[2][0] = M[3][2] = 0;
- M[0][3] = M[1][3] = M[2][1] = M[3][0] = 0;
- }
-
- // Multiplies two matrices into destination with minimum copying.
- static Matrix4f& Multiply(Matrix4f* d, const Matrix4f& a, const Matrix4f& b)
- {
- OVR_ASSERT((d != &a) && (d != &b));
- int i = 0;
- do {
- d->M[i][0] = a.M[i][0] * b.M[0][0] + a.M[i][1] * b.M[1][0] + a.M[i][2] * b.M[2][0] + a.M[i][3] * b.M[3][0];
- d->M[i][1] = a.M[i][0] * b.M[0][1] + a.M[i][1] * b.M[1][1] + a.M[i][2] * b.M[2][1] + a.M[i][3] * b.M[3][1];
- d->M[i][2] = a.M[i][0] * b.M[0][2] + a.M[i][1] * b.M[1][2] + a.M[i][2] * b.M[2][2] + a.M[i][3] * b.M[3][2];
- d->M[i][3] = a.M[i][0] * b.M[0][3] + a.M[i][1] * b.M[1][3] + a.M[i][2] * b.M[2][3] + a.M[i][3] * b.M[3][3];
- } while((++i) < 4);
-
- return *d;
- }
-
- Matrix4f operator* (const Matrix4f& b) const
- {
- Matrix4f result(Matrix4f::NoInit);
- Multiply(&result, *this, b);
- return result;
- }
-
- Matrix4f& operator*= (const Matrix4f& b)
- {
- return Multiply(this, Matrix4f(*this), b);
- }
-
- Matrix4f operator* (float s) const
- {
- return Matrix4f(M[0][0] * s, M[0][1] * s, M[0][2] * s, M[0][3] * s,
- M[1][0] * s, M[1][1] * s, M[1][2] * s, M[1][3] * s,
- M[2][0] * s, M[2][1] * s, M[2][2] * s, M[2][3] * s,
- M[3][0] * s, M[3][1] * s, M[3][2] * s, M[3][3] * s);
- }
-
- Matrix4f& operator*= (float s)
- {
- M[0][0] *= s; M[0][1] *= s; M[0][2] *= s; M[0][3] *= s;
- M[1][0] *= s; M[1][1] *= s; M[1][2] *= s; M[1][3] *= s;
- M[2][0] *= s; M[2][1] *= s; M[2][2] *= s; M[2][3] *= s;
- M[3][0] *= s; M[3][1] *= s; M[3][2] *= s; M[3][3] *= s;
- return *this;
- }
-
- Vector3f Transform(const Vector3f& v) const
- {
- return Vector3f(M[0][0] * v.x + M[0][1] * v.y + M[0][2] * v.z + M[0][3],
- M[1][0] * v.x + M[1][1] * v.y + M[1][2] * v.z + M[1][3],
- M[2][0] * v.x + M[2][1] * v.y + M[2][2] * v.z + M[2][3]);
- }
-
- Matrix4f Transposed() const
- {
- return Matrix4f(M[0][0], M[1][0], M[2][0], M[3][0],
- M[0][1], M[1][1], M[2][1], M[3][1],
- M[0][2], M[1][2], M[2][2], M[3][2],
- M[0][3], M[1][3], M[2][3], M[3][3]);
- }
-
- void Transpose()
- {
- *this = Transposed();
- }
-
-
- float SubDet (const int* rows, const int* cols) const
- {
- return M[rows[0]][cols[0]] * (M[rows[1]][cols[1]] * M[rows[2]][cols[2]] - M[rows[1]][cols[2]] * M[rows[2]][cols[1]])
- - M[rows[0]][cols[1]] * (M[rows[1]][cols[0]] * M[rows[2]][cols[2]] - M[rows[1]][cols[2]] * M[rows[2]][cols[0]])
- + M[rows[0]][cols[2]] * (M[rows[1]][cols[0]] * M[rows[2]][cols[1]] - M[rows[1]][cols[1]] * M[rows[2]][cols[0]]);
- }
-
- float Cofactor(int I, int J) const
- {
- const int indices[4][3] = {{1,2,3},{0,2,3},{0,1,3},{0,1,2}};
- return ((I+J)&1) ? -SubDet(indices[I],indices[J]) : SubDet(indices[I],indices[J]);
- }
-
- float Determinant() const
- {
- return M[0][0] * Cofactor(0,0) + M[0][1] * Cofactor(0,1) + M[0][2] * Cofactor(0,2) + M[0][3] * Cofactor(0,3);
- }
-
- Matrix4f Adjugated() const
- {
- return Matrix4f(Cofactor(0,0), Cofactor(1,0), Cofactor(2,0), Cofactor(3,0),
- Cofactor(0,1), Cofactor(1,1), Cofactor(2,1), Cofactor(3,1),
- Cofactor(0,2), Cofactor(1,2), Cofactor(2,2), Cofactor(3,2),
- Cofactor(0,3), Cofactor(1,3), Cofactor(2,3), Cofactor(3,3));
- }
-
- Matrix4f Inverted() const
- {
- float det = Determinant();
- assert(det != 0);
- return Adjugated() * (1.0f/det);
- }
-
- void Invert()
- {
- *this = Inverted();
- }
-
- //AnnaSteve:
- // a,b,c, are the YawPitchRoll angles to be returned
- // rotation a around axis A1
- // is followed by rotation b around axis A2
- // is followed by rotation c around axis A3
- // rotations are CCW or CW (D) in LH or RH coordinate system (S)
- template <Axis A1, Axis A2, Axis A3, RotateDirection D, HandedSystem S>
- void ToEulerAngles(float *a, float *b, float *c)
- {
- OVR_COMPILER_ASSERT((A1 != A2) && (A2 != A3) && (A1 != A3));
-
- float psign = -1.0f;
- if (((A1 + 1) % 3 == A2) && ((A2 + 1) % 3 == A3)) // Determine whether even permutation
- psign = 1.0f;
-
- float pm = psign*M[A1][A3];
- if (pm < -1.0f + Math<float>::SingularityRadius)
- { // South pole singularity
- *a = 0.0f;
- *b = -S*D*Math<float>::PiOver2;
- *c = S*D*atan2( psign*M[A2][A1], M[A2][A2] );
- }
- else if (pm > 1.0 - Math<float>::SingularityRadius)
- { // North pole singularity
- *a = 0.0f;
- *b = S*D*Math<float>::PiOver2;
- *c = S*D*atan2( psign*M[A2][A1], M[A2][A2] );
- }
- else
- { // Normal case (nonsingular)
- *a = S*D*atan2( -psign*M[A2][A3], M[A3][A3] );
- *b = S*D*asin(pm);
- *c = S*D*atan2( -psign*M[A1][A2], M[A1][A1] );
- }
-
- return;
- }
-
- //AnnaSteve:
- // a,b,c, are the YawPitchRoll angles to be returned
- // rotation a around axis A1
- // is followed by rotation b around axis A2
- // is followed by rotation c around axis A1
- // rotations are CCW or CW (D) in LH or RH coordinate system (S)
- template <Axis A1, Axis A2, RotateDirection D, HandedSystem S>
- void ToEulerAnglesABA(float *a, float *b, float *c)
- {
- OVR_COMPILER_ASSERT(A1 != A2);
-
- // Determine the axis that was not supplied
- int m = 3 - A1 - A2;
-
- float psign = -1.0f;
- if ((A1 + 1) % 3 == A2) // Determine whether even permutation
- psign = 1.0f;
-
- float c2 = M[A1][A1];
- if (c2 < -1.0 + Math<float>::SingularityRadius)
- { // South pole singularity
- *a = 0.0f;
- *b = S*D*Math<float>::Pi;
- *c = S*D*atan2( -psign*M[A2][m],M[A2][A2]);
- }
- else if (c2 > 1.0 - Math<float>::SingularityRadius)
- { // North pole singularity
- *a = 0.0f;
- *b = 0.0f;
- *c = S*D*atan2( -psign*M[A2][m],M[A2][A2]);
- }
- else
- { // Normal case (nonsingular)
- *a = S*D*atan2( M[A2][A1],-psign*M[m][A1]);
- *b = S*D*acos(c2);
- *c = S*D*atan2( M[A1][A2],psign*M[A1][m]);
- }
- return;
- }
-
- // Creates a matrix that converts the vertices from one coordinate system
- // to another.
- //
- static Matrix4f AxisConversion(const WorldAxes& to, const WorldAxes& from)
- {
- // Holds axis values from the 'to' structure
- int toArray[3] = { to.XAxis, to.YAxis, to.ZAxis };
-
- // The inverse of the toArray
- int inv[4];
- inv[0] = inv[abs(to.XAxis)] = 0;
- inv[abs(to.YAxis)] = 1;
- inv[abs(to.ZAxis)] = 2;
-
- Matrix4f m(0, 0, 0,
- 0, 0, 0,
- 0, 0, 0);
-
- // Only three values in the matrix need to be changed to 1 or -1.
- m.M[inv[abs(from.XAxis)]][0] = float(from.XAxis/toArray[inv[abs(from.XAxis)]]);
- m.M[inv[abs(from.YAxis)]][1] = float(from.YAxis/toArray[inv[abs(from.YAxis)]]);
- m.M[inv[abs(from.ZAxis)]][2] = float(from.ZAxis/toArray[inv[abs(from.ZAxis)]]);
- return m;
- }
-
-
-
- static Matrix4f Translation(const Vector3f& v)
- {
- Matrix4f t;
- t.M[0][3] = v.x;
- t.M[1][3] = v.y;
- t.M[2][3] = v.z;
- return t;
- }
-
- static Matrix4f Translation(float x, float y, float z = 0.0f)
- {
- Matrix4f t;
- t.M[0][3] = x;
- t.M[1][3] = y;
- t.M[2][3] = z;
- return t;
- }
-
- static Matrix4f Scaling(const Vector3f& v)
- {
- Matrix4f t;
- t.M[0][0] = v.x;
- t.M[1][1] = v.y;
- t.M[2][2] = v.z;
- return t;
- }
-
- static Matrix4f Scaling(float x, float y, float z)
- {
- Matrix4f t;
- t.M[0][0] = x;
- t.M[1][1] = y;
- t.M[2][2] = z;
- return t;
- }
-
- static Matrix4f Scaling(float s)
- {
- Matrix4f t;
- t.M[0][0] = s;
- t.M[1][1] = s;
- t.M[2][2] = s;
- return t;
- }
-
-
-
- //AnnaSteve : Just for quick testing. Not for final API. Need to remove case.
- static Matrix4f RotationAxis(Axis A, float angle, RotateDirection d, HandedSystem s)
- {
- float sina = s * d *sin(angle);
- float cosa = cos(angle);
-
- switch(A)
- {
- case Axis_X:
- return Matrix4f(1, 0, 0,
- 0, cosa, -sina,
- 0, sina, cosa);
- case Axis_Y:
- return Matrix4f(cosa, 0, sina,
- 0, 1, 0,
- -sina, 0, cosa);
- case Axis_Z:
- return Matrix4f(cosa, -sina, 0,
- sina, cosa, 0,
- 0, 0, 1);
- }
- }
-
-
- // Creates a rotation matrix rotating around the X axis by 'angle' radians.
- // Rotation direction is depends on the coordinate system:
- // RHS (Oculus default): Positive angle values rotate Counter-clockwise (CCW),
- // while looking in the negative axis direction. This is the
- // same as looking down from positive axis values towards origin.
- // LHS: Positive angle values rotate clock-wise (CW), while looking in the
- // negative axis direction.
- static Matrix4f RotationX(float angle)
- {
- float sina = sin(angle);
- float cosa = cos(angle);
- return Matrix4f(1, 0, 0,
- 0, cosa, -sina,
- 0, sina, cosa);
- }
-
- // Creates a rotation matrix rotating around the Y axis by 'angle' radians.
- // Rotation direction is depends on the coordinate system:
- // RHS (Oculus default): Positive angle values rotate Counter-clockwise (CCW),
- // while looking in the negative axis direction. This is the
- // same as looking down from positive axis values towards origin.
- // LHS: Positive angle values rotate clock-wise (CW), while looking in the
- // negative axis direction.
- static Matrix4f RotationY(float angle)
- {
- float sina = sin(angle);
- float cosa = cos(angle);
- return Matrix4f(cosa, 0, sina,
- 0, 1, 0,
- -sina, 0, cosa);
- }
-
- // Creates a rotation matrix rotating around the Z axis by 'angle' radians.
- // Rotation direction is depends on the coordinate system:
- // RHS (Oculus default): Positive angle values rotate Counter-clockwise (CCW),
- // while looking in the negative axis direction. This is the
- // same as looking down from positive axis values towards origin.
- // LHS: Positive angle values rotate clock-wise (CW), while looking in the
- // negative axis direction.
- static Matrix4f RotationZ(float angle)
- {
- float sina = sin(angle);
- float cosa = cos(angle);
- return Matrix4f(cosa, -sina, 0,
- sina, cosa, 0,
- 0, 0, 1);
- }
-
-
- // LookAtRH creates a View transformation matrix for right-handed coordinate system.
- // The resulting matrix points camera from 'eye' towards 'at' direction, with 'up'
- // specifying the up vector. The resulting matrix should be used with PerspectiveRH
- // projection.
- static Matrix4f LookAtRH(const Vector3f& eye, const Vector3f& at, const Vector3f& up);
-
- // LookAtLH creates a View transformation matrix for left-handed coordinate system.
- // The resulting matrix points camera from 'eye' towards 'at' direction, with 'up'
- // specifying the up vector.
- static Matrix4f LookAtLH(const Vector3f& eye, const Vector3f& at, const Vector3f& up);
-
-
- // PerspectiveRH creates a right-handed perspective projection matrix that can be
- // used with the Oculus sample renderer.
- // yfov - Specifies vertical field of view in radians.
- // aspect - Screen aspect ration, which is usually width/height for square pixels.
- // Note that xfov = yfov * aspect.
- // znear - Absolute value of near Z clipping clipping range.
- // zfar - Absolute value of far Z clipping clipping range (larger then near).
- // Even though RHS usually looks in the direction of negative Z, positive values
- // are expected for znear and zfar.
- static Matrix4f PerspectiveRH(float yfov, float aspect, float znear, float zfar);
-
-
- // PerspectiveRH creates a left-handed perspective projection matrix that can be
- // used with the Oculus sample renderer.
- // yfov - Specifies vertical field of view in radians.
- // aspect - Screen aspect ration, which is usually width/height for square pixels.
- // Note that xfov = yfov * aspect.
- // znear - Absolute value of near Z clipping clipping range.
- // zfar - Absolute value of far Z clipping clipping range (larger then near).
- static Matrix4f PerspectiveLH(float yfov, float aspect, float znear, float zfar);
-
-
- static Matrix4f Ortho2D(float w, float h);
-};
-
-
-//-------------------------------------------------------------------------------------
-// ***** Quat
-
-// Quatf represents a quaternion class used for rotations.
-//
-// Quaternion multiplications are done in right-to-left order, to match the
-// behavior of matrices.
-
-
-template<class T>
-class Quat
-{
-public:
- // w + Xi + Yj + Zk
- T x, y, z, w;
-
- Quat() : x(0), y(0), z(0), w(1) {}
- Quat(T x_, T y_, T z_, T w_) : x(x_), y(y_), z(z_), w(w_) {}
-
-
- // Constructs rotation quaternion around the axis.
- Quat(const Vector3<T>& axis, T angle)
- {
- Vector3<T> unitAxis = axis.Normalized();
- T sinHalfAngle = sin(angle * T(0.5));
-
- w = cos(angle * T(0.5));
- x = unitAxis.x * sinHalfAngle;
- y = unitAxis.y * sinHalfAngle;
- z = unitAxis.z * sinHalfAngle;
- }
-
- //AnnaSteve:
- void AxisAngle(Axis A, T angle, RotateDirection d, HandedSystem s)
- {
- T sinHalfAngle = s * d *sin(angle * (T)0.5);
- T v[3];
- v[0] = v[1] = v[2] = (T)0;
- v[A] = sinHalfAngle;
- //return Quat(v[0], v[1], v[2], cos(angle * (T)0.5));
- w = cos(angle * (T)0.5);
- x = v[0];
- y = v[1];
- z = v[2];
- }
-
-
- void GetAxisAngle(Vector3<T>* axis, T* angle) const
- {
- if (LengthSq() > Math<T>::Tolerance * Math<T>::Tolerance)
- {
- *axis = Vector3<T>(x, y, z).Normalized();
- *angle = 2 * acos(w);
- }
- else
- {
- *axis = Vector3<T>(1, 0, 0);
- *angle= 0;
- }
- }
-
- bool operator== (const Quat& b) const { return x == b.x && y == b.y && z == b.z && w == b.w; }
- bool operator!= (const Quat& b) const { return x != b.x || y != b.y || z != b.z || w != b.w; }
-
- Quat operator+ (const Quat& b) const { return Quat(x + b.x, y + b.y, z + b.z, w + b.w); }
- Quat& operator+= (const Quat& b) { w += b.w; x += b.x; y += b.y; z += b.z; return *this; }
- Quat operator- (const Quat& b) const { return Quat(x - b.x, y - b.y, z - b.z, w - b.w); }
- Quat& operator-= (const Quat& b) { w -= b.w; x -= b.x; y -= b.y; z -= b.z; return *this; }
-
- Quat operator* (T s) const { return Quat(x * s, y * s, z * s, w * s); }
- Quat& operator*= (T s) { w *= s; x *= s; y *= s; z *= s; return *this; }
- Quat operator/ (T s) const { T rcp = T(1)/s; return Quat(x * rcp, y * rcp, z * rcp, w *rcp); }
- Quat& operator/= (T s) { T rcp = T(1)/s; w *= rcp; x *= rcp; y *= rcp; z *= rcp; return *this; }
-
- // Get Imaginary part vector
- Vector3<T> Imag() const { return Vector3<T>(x,y,z); }
-
- // Get quaternion length.
- T Length() const { return sqrt(x * x + y * y + z * z + w * w); }
- // Get quaternion length squared.
- T LengthSq() const { return (x * x + y * y + z * z + w * w); }
- // Simple Eulidean distance in R^4 (not SLERP distance, but at least respects Haar measure)
- T Distance(const Quat& q) const
- {
- T d1 = (*this - q).Length();
- T d2 = (*this + q).Length(); // Antipoldal point check
- return (d1 < d2) ? d1 : d2;
- }
- T DistanceSq(const Quat& q) const
- {
- T d1 = (*this - q).LengthSq();
- T d2 = (*this + q).LengthSq(); // Antipoldal point check
- return (d1 < d2) ? d1 : d2;
- }
-
- // Normalize
- bool IsNormalized() const { return fabs(LengthSq() - 1) < Math<T>::Tolerance; }
- void Normalize() { *this /= Length(); }
- Quat Normalized() const { return *this / Length(); }
-
- // Returns conjugate of the quaternion. Produces inverse rotation if quaternion is normalized.
- Quat Conj() const { return Quat(-x, -y, -z, w); }
-
- // AnnaSteve fixed: order of quaternion multiplication
- // Quaternion multiplication. Combines quaternion rotations, performing the one on the
- // right hand side first.
- Quat operator* (const Quat& b) const { return Quat(w * b.x + x * b.w + y * b.z - z * b.y,
- w * b.y - x * b.z + y * b.w + z * b.x,
- w * b.z + x * b.y - y * b.x + z * b.w,
- w * b.w - x * b.x - y * b.y - z * b.z); }
-
- //
- // this^p normalized; same as rotating by this p times.
- Quat PowNormalized(T p) const
- {
- Vector3<T> v;
- T a;
- GetAxisAngle(&v, &a);
- return Quat(v, a * p);
- }
-
- // Rotate transforms vector in a manner that matches Matrix rotations (counter-clockwise,
- // assuming negative direction of the axis). Standard formula: q(t) * V * q(t)^-1.
- Vector3<T> Rotate(const Vector3<T>& v) const
- {
- return ((*this * Quat<T>(v.x, v.y, v.z, 0)) * Inverted()).Imag();
- }
-
-
- // Inversed quaternion rotates in the opposite direction.
- Quat Inverted() const
- {
- return Quat(-x, -y, -z, w);
- }
-
- // Sets this quaternion to the one rotates in the opposite direction.
- void Invert() const
- {
- *this = Quat(-x, -y, -z, w);
- }
-
- // Converting quaternion to matrix.
- operator Matrix4f() const
- {
- T ww = w*w;
- T xx = x*x;
- T yy = y*y;
- T zz = z*z;
-
- return Matrix4f(float(ww + xx - yy - zz), float(T(2) * (x*y - w*z)), float(T(2) * (x*z + w*y)),
- float(T(2) * (x*y + w*z)), float(ww - xx + yy - zz), float(T(2) * (y*z - w*x)),
- float(T(2) * (x*z - w*y)), float(T(2) * (y*z + w*x)), float(ww - xx - yy + zz) );
- }
-
-
- // GetEulerAngles extracts Euler angles from the quaternion, in the specified order of
- // axis rotations and the specified coordinate system. Right-handed coordinate system
- // is the default, with CCW rotations while looking in the negative axis direction.
- // Here a,b,c, are the Yaw/Pitch/Roll angles to be returned.
- // rotation a around axis A1
- // is followed by rotation b around axis A2
- // is followed by rotation c around axis A3
- // rotations are CCW or CW (D) in LH or RH coordinate system (S)
- template <Axis A1, Axis A2, Axis A3, RotateDirection D, HandedSystem S>
- void GetEulerAngles(T *a, T *b, T *c)
- {
- OVR_COMPILER_ASSERT((A1 != A2) && (A2 != A3) && (A1 != A3));
-
- T Q[3] = { x, y, z }; //Quaternion components x,y,z
-
- T ww = w*w;
- T Q11 = Q[A1]*Q[A1];
- T Q22 = Q[A2]*Q[A2];
- T Q33 = Q[A3]*Q[A3];
-
- T psign = T(-1.0);
- // Determine whether even permutation
- if (((A1 + 1) % 3 == A2) && ((A2 + 1) % 3 == A3))
- psign = T(1.0);
-
- T s2 = psign * T(2.0) * (psign*w*Q[A2] + Q[A1]*Q[A3]);
-
- if (s2 < (T)-1.0 + Math<T>::SingularityRadius)
- { // South pole singularity
- *a = T(0.0);
- *b = -S*D*Math<T>::PiOver2;
- *c = S*D*atan2((T)2.0*(psign*Q[A1]*Q[A2] + w*Q[A3]),
- ww + Q22 - Q11 - Q33 );
- }
- else if (s2 > (T)1.0 - Math<T>::SingularityRadius)
- { // North pole singularity
- *a = (T)0.0;
- *b = S*D*Math<T>::PiOver2;
- *c = S*D*atan2((T)2.0*(psign*Q[A1]*Q[A2] + w*Q[A3]),
- ww + Q22 - Q11 - Q33);
- }
- else
- {
- *a = -S*D*atan2((T)-2.0*(w*Q[A1] - psign*Q[A2]*Q[A3]),
- ww + Q33 - Q11 - Q22);
- *b = S*D*asin(s2);
- *c = S*D*atan2((T)2.0*(w*Q[A3] - psign*Q[A1]*Q[A2]),
- ww + Q11 - Q22 - Q33);
- }
- return;
- }
-
- template <Axis A1, Axis A2, Axis A3, RotateDirection D>
- void GetEulerAngles(T *a, T *b, T *c)
- { GetEulerAngles<A1, A2, A3, D, Handed_R>(a, b, c); }
-
- template <Axis A1, Axis A2, Axis A3>
- void GetEulerAngles(T *a, T *b, T *c)
- { GetEulerAngles<A1, A2, A3, Rotate_CCW, Handed_R>(a, b, c); }
-
-
- // GetEulerAnglesABA extracts Euler angles from the quaternion, in the specified order of
- // axis rotations and the specified coordinate system. Right-handed coordinate system
- // is the default, with CCW rotations while looking in the negative axis direction.
- // Here a,b,c, are the Yaw/Pitch/Roll angles to be returned.
- // rotation a around axis A1
- // is followed by rotation b around axis A2
- // is followed by rotation c around axis A1
- // Rotations are CCW or CW (D) in LH or RH coordinate system (S)
- template <Axis A1, Axis A2, RotateDirection D, HandedSystem S>
- void GetEulerAnglesABA(T *a, T *b, T *c)
- {
- OVR_COMPILER_ASSERT(A1 != A2);
-
- T Q[3] = {x, y, z}; // Quaternion components
-
- // Determine the missing axis that was not supplied
- int m = 3 - A1 - A2;
-
- T ww = w*w;
- T Q11 = Q[A1]*Q[A1];
- T Q22 = Q[A2]*Q[A2];
- T Qmm = Q[m]*Q[m];
-
- T psign = T(-1.0);
- if ((A1 + 1) % 3 == A2) // Determine whether even permutation
- {
- psign = (T)1.0;
- }
-
- T c2 = ww + Q11 - Q22 - Qmm;
- if (c2 < (T)-1.0 + Math<T>::SingularityRadius)
- { // South pole singularity
- *a = (T)0.0;
- *b = S*D*Math<T>::Pi;
- *c = S*D*atan2( (T)2.0*(w*Q[A1] - psign*Q[A2]*Q[m]),
- ww + Q22 - Q11 - Qmm);
- }
- else if (c2 > (T)1.0 - Math<T>::SingularityRadius)
- { // North pole singularity
- *a = (T)0.0;
- *b = (T)0.0;
- *c = S*D*atan2( (T)2.0*(w*Q[A1] - psign*Q[A2]*Q[m]),
- ww + Q22 - Q11 - Qmm);
- }
- else
- {
- *a = S*D*atan2( psign*w*Q[m] + Q[A1]*Q[A2],
- w*Q[A2] -psign*Q[A1]*Q[m]);
- *b = S*D*acos(c2);
- *c = S*D*atan2( -psign*w*Q[m] + Q[A1]*Q[A2],
- w*Q[A2] + psign*Q[A1]*Q[m]);
- }
- return;
- }
-};
-
-
-typedef Quat<float> Quatf;
-typedef Quat<double> Quatd;
-
-//-------------------------------------------------------------------------------------
-// ***** Plane
-
-// Consists of a normal vector and distance from the origin where the plane is located.
-
-template<class T>
-class Plane : public RefCountBase<Plane<T> >
-{
-public:
- Vector3<T> N;
- T D;
-
- Plane() : D(0) {}
-
- // Normals must already be normalized
- Plane(const Vector3<T>& n, T d) : N(n), D(d) {}
- Plane(T x, T y, T z, T d) : N(x,y,z), D(d) {}
-
- // construct from a point on the plane and the normal
- Plane(const Vector3<T>& p, const Vector3<T>& n) : N(n), D(-(p * n)) {}
-
- // Find the point to plane distance. The sign indicates what side of the plane the point is on (0 = point on plane).
- T TestSide(const Vector3<T>& p) const
- {
- return (N * p) + D;
- }
-
- Plane<T> Flipped() const
- {
- return Plane(-N, -D);
- }
-
- void Flip()
- {
- N = -N;
- D = -D;
- }
-
- bool operator==(const Plane<T>& rhs) const
- {
- return (this->D == rhs.D && this->N == rhs.N);
- }
-};
-
-typedef Plane<float> Planef;
-
-}
-
-#endif
+/************************************************************************************
+
+PublicHeader: OVR.h
+Filename : OVR_Math.h
+Content : Implementation of 3D primitives such as vectors, matrices.
+Created : September 4, 2012
+Authors : Andrew Reisse, Michael Antonov, Steve LaValle, Anna Yershova
+
+Copyright : Copyright 2012 Oculus VR, Inc. All Rights reserved.
+
+Use of this software is subject to the terms of the Oculus license
+agreement provided at the time of installation or download, or which
+otherwise accompanies this software in either electronic or hard copy form.
+
+*************************************************************************************/
+
+#ifndef OVR_Math_h
+#define OVR_Math_h
+
+#include <assert.h>
+#include <stdlib.h>
+#include <math.h>
+
+#include "OVR_Types.h"
+#include "OVR_RefCount.h"
+
+namespace OVR {
+
+//-------------------------------------------------------------------------------------
+// Constants for 3D world/axis definitions.
+
+// Definitions of axes for coordinate and rotation conversions.
+enum Axis
+{
+ Axis_X = 0, Axis_Y = 1, Axis_Z = 2
+};
+
+// RotateDirection describes the rotation direction around an axis, interpreted as follows:
+// CW - Clockwise while looking "down" from positive axis towards the origin.
+// CCW - Counter-clockwise while looking from the positive axis towards the origin,
+// which is in the negative axis direction.
+// CCW is the default for the RHS coordinate system. Oculus standard RHS coordinate
+// system defines Y up, X right, and Z back (pointing out from the screen). In this
+// system Rotate_CCW around Z will specifies counter-clockwise rotation in XY plane.
+enum RotateDirection
+{
+ Rotate_CCW = 1,
+ Rotate_CW = -1
+};
+
+enum HandedSystem
+{
+ Handed_R = 1, Handed_L = -1
+};
+
+// AxisDirection describes which way the axis points. Used by WorldAxes.
+enum AxisDirection
+{
+ Axis_Up = 2,
+ Axis_Down = -2,
+ Axis_Right = 1,
+ Axis_Left = -1,
+ Axis_In = 3,
+ Axis_Out = -3
+};
+
+struct WorldAxes
+{
+ AxisDirection XAxis, YAxis, ZAxis;
+
+ WorldAxes(AxisDirection x, AxisDirection y, AxisDirection z)
+ : XAxis(x), YAxis(y), ZAxis(z)
+ { OVR_ASSERT(abs(x) != abs(y) && abs(y) != abs(z) && abs(z) != abs(x));}
+};
+
+
+//-------------------------------------------------------------------------------------
+// ***** Math
+
+// Math class contains constants and functions. This class is a template specialized
+// per type, with Math<float> and Math<double> being distinct.
+template<class Type>
+class Math
+{
+};
+
+// Single-precision Math constants class.
+template<>
+class Math<float>
+{
+public:
+ static const float Pi;
+ static const float TwoPi;
+ static const float PiOver2;
+ static const float PiOver4;
+ static const float E;
+
+ static const float MaxValue; // Largest positive float Value
+ static const float MinPositiveValue; // Smallest possible positive value
+
+ static const float RadToDegreeFactor;
+ static const float DegreeToRadFactor;
+
+ static const float Tolerance; // 0.00001f;
+ static const float SingularityRadius; //0.00000000001f for Gimbal lock numerical problems
+};
+
+// Double-precision Math constants class.
+template<>
+class Math<double>
+{
+public:
+ static const double Pi;
+ static const double TwoPi;
+ static const double PiOver2;
+ static const double PiOver4;
+ static const double E;
+
+ static const double MaxValue; // Largest positive double Value
+ static const double MinPositiveValue; // Smallest possible positive value
+
+ static const double RadToDegreeFactor;
+ static const double DegreeToRadFactor;
+
+ static const double Tolerance; // 0.00001f;
+ static const double SingularityRadius; //0.00000000001 for Gimbal lock numerical problems
+};
+
+typedef Math<float> Mathf;
+typedef Math<double> Mathd;
+
+// Conversion functions between degrees and radians
+template<class FT>
+FT RadToDegree(FT rads) { return rads * Math<FT>::RadToDegreeFactor; }
+template<class FT>
+FT DegreeToRad(FT rads) { return rads * Math<FT>::DegreeToRadFactor; }
+
+template<class T>
+class Quat;
+
+//-------------------------------------------------------------------------------------
+// ***** Vector2f - 2D Vector2f
+
+// Vector2f represents a 2-dimensional vector or point in space,
+// consisting of coordinates x and y,
+
+template<class T>
+class Vector2
+{
+public:
+ T x, y;
+
+ Vector2() : x(0), y(0) { }
+ Vector2(T x_, T y_) : x(x_), y(y_) { }
+ explicit Vector2(T s) : x(s), y(s) { }
+
+ bool operator== (const Vector2& b) const { return x == b.x && y == b.y; }
+ bool operator!= (const Vector2& b) const { return x != b.x || y != b.y; }
+
+ Vector2 operator+ (const Vector2& b) const { return Vector2(x + b.x, y + b.y); }
+ Vector2& operator+= (const Vector2& b) { x += b.x; y += b.y; return *this; }
+ Vector2 operator- (const Vector2& b) const { return Vector2(x - b.x, y - b.y); }
+ Vector2& operator-= (const Vector2& b) { x -= b.x; y -= b.y; return *this; }
+ Vector2 operator- () const { return Vector2(-x, -y); }
+
+ // Scalar multiplication/division scales vector.
+ Vector2 operator* (T s) const { return Vector2(x*s, y*s); }
+ Vector2& operator*= (T s) { x *= s; y *= s; return *this; }
+
+ Vector2 operator/ (T s) const { T rcp = T(1)/s;
+ return Vector2(x*rcp, y*rcp); }
+ Vector2& operator/= (T s) { T rcp = T(1)/s;
+ x *= rcp; y *= rcp;
+ return *this; }
+
+ // Compare two vectors for equality with tolerance. Returns true if vectors match withing tolerance.
+ bool Compare(const Vector2&b, T tolerance = Mathf::Tolerance)
+ {
+ return (fabs(b.x-x) < tolerance) && (fabs(b.y-y) < tolerance);
+ }
+
+ // Dot product overload.
+ // Used to calculate angle q between two vectors among other things,
+ // as (A dot B) = |a||b|cos(q).
+ T operator* (const Vector2& b) const { return x*b.x + y*b.y; }
+
+ // Returns the angle from this vector to b, in radians.
+ T Angle(const Vector2& b) const { return acos((*this * b)/(Length()*b.Length())); }
+
+ // Return Length of the vector squared.
+ T LengthSq() const { return (x * x + y * y); }
+ // Return vector length.
+ T Length() const { return sqrt(LengthSq()); }
+
+ // Returns distance between two points represented by vectors.
+ T Distance(Vector2& b) const { return (*this - b).Length(); }
+
+ // Determine if this a unit vector.
+ bool IsNormalized() const { return fabs(LengthSq() - T(1)) < Math<T>::Tolerance; }
+ // Normalize, convention vector length to 1.
+ void Normalize() { *this /= Length(); }
+ // Returns normalized (unit) version of the vector without modifying itself.
+ Vector2 Normalized() const { return *this / Length(); }
+
+ // Linearly interpolates from this vector to another.
+ // Factor should be between 0.0 and 1.0, with 0 giving full value to this.
+ Vector2 Lerp(const Vector2& b, T f) const { return *this*(T(1) - f) + b*f; }
+
+ // Projects this vector onto the argument; in other words,
+ // A.Project(B) returns projection of vector A onto B.
+ Vector2 ProjectTo(const Vector2& b) const { return b * ((*this * b) / b.LengthSq()); }
+};
+
+
+typedef Vector2<float> Vector2f;
+typedef Vector2<double> Vector2d;
+
+//-------------------------------------------------------------------------------------
+// ***** Vector3f - 3D Vector3f
+
+// Vector3f represents a 3-dimensional vector or point in space,
+// consisting of coordinates x, y and z.
+
+template<class T>
+class Vector3
+{
+public:
+ T x, y, z;
+
+ Vector3() : x(0), y(0), z(0) { }
+ Vector3(T x_, T y_, T z_ = 0) : x(x_), y(y_), z(z_) { }
+ explicit Vector3(T s) : x(s), y(s), z(s) { }
+
+ bool operator== (const Vector3& b) const { return x == b.x && y == b.y && z == b.z; }
+ bool operator!= (const Vector3& b) const { return x != b.x || y != b.y || z != b.z; }
+
+ Vector3 operator+ (const Vector3& b) const { return Vector3(x + b.x, y + b.y, z + b.z); }
+ Vector3& operator+= (const Vector3& b) { x += b.x; y += b.y; z += b.z; return *this; }
+ Vector3 operator- (const Vector3& b) const { return Vector3(x - b.x, y - b.y, z - b.z); }
+ Vector3& operator-= (const Vector3& b) { x -= b.x; y -= b.y; z -= b.z; return *this; }
+ Vector3 operator- () const { return Vector3(-x, -y, -z); }
+
+ // Scalar multiplication/division scales vector.
+ Vector3 operator* (T s) const { return Vector3(x*s, y*s, z*s); }
+ Vector3& operator*= (T s) { x *= s; y *= s; z *= s; return *this; }
+
+ Vector3 operator/ (T s) const { T rcp = T(1)/s;
+ return Vector3(x*rcp, y*rcp, z*rcp); }
+ Vector3& operator/= (T s) { T rcp = T(1)/s;
+ x *= rcp; y *= rcp; z *= rcp;
+ return *this; }
+
+ // Compare two vectors for equality with tolerance. Returns true if vectors match withing tolerance.
+ bool Compare(const Vector3&b, T tolerance = Mathf::Tolerance)
+ {
+ return (fabs(b.x-x) < tolerance) && (fabs(b.y-y) < tolerance) && (fabs(b.z-z) < tolerance);
+ }
+
+ // Dot product overload.
+ // Used to calculate angle q between two vectors among other things,
+ // as (A dot B) = |a||b|cos(q).
+ T operator* (const Vector3& b) const { return x*b.x + y*b.y + z*b.z; }
+
+ // Compute cross product, which generates a normal vector.
+ // Direction vector can be determined by right-hand rule: Pointing index finder in
+ // direction a and middle finger in direction b, thumb will point in a.Cross(b).
+ Vector3 Cross(const Vector3& b) const { return Vector3(y*b.z - z*b.y,
+ z*b.x - x*b.z,
+ x*b.y - y*b.x); }
+
+ // Returns the angle from this vector to b, in radians.
+ T Angle(const Vector3& b) const { return acos((*this * b)/(Length()*b.Length())); }
+
+ // Return Length of the vector squared.
+ T LengthSq() const { return (x * x + y * y + z * z); }
+ // Return vector length.
+ T Length() const { return sqrt(LengthSq()); }
+
+ // Returns distance between two points represented by vectors.
+ T Distance(Vector3& b) const { return (*this - b).Length(); }
+
+ // Determine if this a unit vector.
+ bool IsNormalized() const { return fabs(LengthSq() - T(1)) < Math<T>::Tolerance; }
+ // Normalize, convention vector length to 1.
+ void Normalize() { *this /= Length(); }
+ // Returns normalized (unit) version of the vector without modifying itself.
+ Vector3 Normalized() const { return *this / Length(); }
+
+ // Linearly interpolates from this vector to another.
+ // Factor should be between 0.0 and 1.0, with 0 giving full value to this.
+ Vector3 Lerp(const Vector3& b, T f) const { return *this*(T(1) - f) + b*f; }
+
+ // Projects this vector onto the argument; in other words,
+ // A.Project(B) returns projection of vector A onto B.
+ Vector3 ProjectTo(const Vector3& b) const { return b * ((*this * b) / b.LengthSq()); }
+};
+
+
+typedef Vector3<float> Vector3f;
+typedef Vector3<double> Vector3d;
+
+
+//-------------------------------------------------------------------------------------
+// ***** Matrix4f
+
+// Matrix4f is a 4x4 matrix used for 3d transformations and projections.
+// Translation stored in the last column.
+// The matrix is stored in row-major order in memory, meaning that values
+// of the first row are stored before the next one.
+//
+// The arrangement of the matrix is chosen to be in Right-Handed
+// coordinate system and counterclockwise rotations when looking down
+// the axis
+//
+// Transformation Order:
+// - Transformations are applied from right to left, so the expression
+// M1 * M2 * M3 * V means that the vector V is transformed by M3 first,
+// followed by M2 and M1.
+//
+// Coordinate system: Right Handed
+//
+// Rotations: Counterclockwise when looking down the axis. All angles are in radians.
+//
+// | sx 01 02 tx | // First column (sx, 10, 20): Axis X basis vector.
+// | 10 sy 12 ty | // Second column (01, sy, 21): Axis Y basis vector.
+// | 20 21 sz tz | // Third columnt (02, 12, sz): Axis Z basis vector.
+// | 30 31 32 33 |
+//
+// The basis vectors are first three columns.
+
+class Matrix4f
+{
+ static Matrix4f IdentityValue;
+
+public:
+ float M[4][4];
+
+ enum NoInitType { NoInit };
+
+ // Construct with no memory initialization.
+ Matrix4f(NoInitType) { }
+
+ // By default, we construct identity matrix.
+ Matrix4f()
+ {
+ SetIdentity();
+ }
+
+ Matrix4f(float m11, float m12, float m13, float m14,
+ float m21, float m22, float m23, float m24,
+ float m31, float m32, float m33, float m34,
+ float m41, float m42, float m43, float m44)
+ {
+ M[0][0] = m11; M[0][1] = m12; M[0][2] = m13; M[0][3] = m14;
+ M[1][0] = m21; M[1][1] = m22; M[1][2] = m23; M[1][3] = m24;
+ M[2][0] = m31; M[2][1] = m32; M[2][2] = m33; M[2][3] = m34;
+ M[3][0] = m41; M[3][1] = m42; M[3][2] = m43; M[3][3] = m44;
+ }
+
+ Matrix4f(float m11, float m12, float m13,
+ float m21, float m22, float m23,
+ float m31, float m32, float m33)
+ {
+ M[0][0] = m11; M[0][1] = m12; M[0][2] = m13; M[0][3] = 0;
+ M[1][0] = m21; M[1][1] = m22; M[1][2] = m23; M[1][3] = 0;
+ M[2][0] = m31; M[2][1] = m32; M[2][2] = m33; M[2][3] = 0;
+ M[3][0] = 0; M[3][1] = 0; M[3][2] = 0; M[3][3] = 1;
+ }
+
+ static const Matrix4f& Identity() { return IdentityValue; }
+
+ void SetIdentity()
+ {
+ M[0][0] = M[1][1] = M[2][2] = M[3][3] = 1;
+ M[0][1] = M[1][0] = M[2][3] = M[3][1] = 0;
+ M[0][2] = M[1][2] = M[2][0] = M[3][2] = 0;
+ M[0][3] = M[1][3] = M[2][1] = M[3][0] = 0;
+ }
+
+ // Multiplies two matrices into destination with minimum copying.
+ static Matrix4f& Multiply(Matrix4f* d, const Matrix4f& a, const Matrix4f& b)
+ {
+ OVR_ASSERT((d != &a) && (d != &b));
+ int i = 0;
+ do {
+ d->M[i][0] = a.M[i][0] * b.M[0][0] + a.M[i][1] * b.M[1][0] + a.M[i][2] * b.M[2][0] + a.M[i][3] * b.M[3][0];
+ d->M[i][1] = a.M[i][0] * b.M[0][1] + a.M[i][1] * b.M[1][1] + a.M[i][2] * b.M[2][1] + a.M[i][3] * b.M[3][1];
+ d->M[i][2] = a.M[i][0] * b.M[0][2] + a.M[i][1] * b.M[1][2] + a.M[i][2] * b.M[2][2] + a.M[i][3] * b.M[3][2];
+ d->M[i][3] = a.M[i][0] * b.M[0][3] + a.M[i][1] * b.M[1][3] + a.M[i][2] * b.M[2][3] + a.M[i][3] * b.M[3][3];
+ } while((++i) < 4);
+
+ return *d;
+ }
+
+ Matrix4f operator* (const Matrix4f& b) const
+ {
+ Matrix4f result(Matrix4f::NoInit);
+ Multiply(&result, *this, b);
+ return result;
+ }
+
+ Matrix4f& operator*= (const Matrix4f& b)
+ {
+ return Multiply(this, Matrix4f(*this), b);
+ }
+
+ Matrix4f operator* (float s) const
+ {
+ return Matrix4f(M[0][0] * s, M[0][1] * s, M[0][2] * s, M[0][3] * s,
+ M[1][0] * s, M[1][1] * s, M[1][2] * s, M[1][3] * s,
+ M[2][0] * s, M[2][1] * s, M[2][2] * s, M[2][3] * s,
+ M[3][0] * s, M[3][1] * s, M[3][2] * s, M[3][3] * s);
+ }
+
+ Matrix4f& operator*= (float s)
+ {
+ M[0][0] *= s; M[0][1] *= s; M[0][2] *= s; M[0][3] *= s;
+ M[1][0] *= s; M[1][1] *= s; M[1][2] *= s; M[1][3] *= s;
+ M[2][0] *= s; M[2][1] *= s; M[2][2] *= s; M[2][3] *= s;
+ M[3][0] *= s; M[3][1] *= s; M[3][2] *= s; M[3][3] *= s;
+ return *this;
+ }
+
+ Vector3f Transform(const Vector3f& v) const
+ {
+ return Vector3f(M[0][0] * v.x + M[0][1] * v.y + M[0][2] * v.z + M[0][3],
+ M[1][0] * v.x + M[1][1] * v.y + M[1][2] * v.z + M[1][3],
+ M[2][0] * v.x + M[2][1] * v.y + M[2][2] * v.z + M[2][3]);
+ }
+
+ Matrix4f Transposed() const
+ {
+ return Matrix4f(M[0][0], M[1][0], M[2][0], M[3][0],
+ M[0][1], M[1][1], M[2][1], M[3][1],
+ M[0][2], M[1][2], M[2][2], M[3][2],
+ M[0][3], M[1][3], M[2][3], M[3][3]);
+ }
+
+ void Transpose()
+ {
+ *this = Transposed();
+ }
+
+
+ float SubDet (const int* rows, const int* cols) const
+ {
+ return M[rows[0]][cols[0]] * (M[rows[1]][cols[1]] * M[rows[2]][cols[2]] - M[rows[1]][cols[2]] * M[rows[2]][cols[1]])
+ - M[rows[0]][cols[1]] * (M[rows[1]][cols[0]] * M[rows[2]][cols[2]] - M[rows[1]][cols[2]] * M[rows[2]][cols[0]])
+ + M[rows[0]][cols[2]] * (M[rows[1]][cols[0]] * M[rows[2]][cols[1]] - M[rows[1]][cols[1]] * M[rows[2]][cols[0]]);
+ }
+
+ float Cofactor(int I, int J) const
+ {
+ const int indices[4][3] = {{1,2,3},{0,2,3},{0,1,3},{0,1,2}};
+ return ((I+J)&1) ? -SubDet(indices[I],indices[J]) : SubDet(indices[I],indices[J]);
+ }
+
+ float Determinant() const
+ {
+ return M[0][0] * Cofactor(0,0) + M[0][1] * Cofactor(0,1) + M[0][2] * Cofactor(0,2) + M[0][3] * Cofactor(0,3);
+ }
+
+ Matrix4f Adjugated() const
+ {
+ return Matrix4f(Cofactor(0,0), Cofactor(1,0), Cofactor(2,0), Cofactor(3,0),
+ Cofactor(0,1), Cofactor(1,1), Cofactor(2,1), Cofactor(3,1),
+ Cofactor(0,2), Cofactor(1,2), Cofactor(2,2), Cofactor(3,2),
+ Cofactor(0,3), Cofactor(1,3), Cofactor(2,3), Cofactor(3,3));
+ }
+
+ Matrix4f Inverted() const
+ {
+ float det = Determinant();
+ assert(det != 0);
+ return Adjugated() * (1.0f/det);
+ }
+
+ void Invert()
+ {
+ *this = Inverted();
+ }
+
+ //AnnaSteve:
+ // a,b,c, are the YawPitchRoll angles to be returned
+ // rotation a around axis A1
+ // is followed by rotation b around axis A2
+ // is followed by rotation c around axis A3
+ // rotations are CCW or CW (D) in LH or RH coordinate system (S)
+ template <Axis A1, Axis A2, Axis A3, RotateDirection D, HandedSystem S>
+ void ToEulerAngles(float *a, float *b, float *c)
+ {
+ OVR_COMPILER_ASSERT((A1 != A2) && (A2 != A3) && (A1 != A3));
+
+ float psign = -1.0f;
+ if (((A1 + 1) % 3 == A2) && ((A2 + 1) % 3 == A3)) // Determine whether even permutation
+ psign = 1.0f;
+
+ float pm = psign*M[A1][A3];
+ if (pm < -1.0f + Math<float>::SingularityRadius)
+ { // South pole singularity
+ *a = 0.0f;
+ *b = -S*D*Math<float>::PiOver2;
+ *c = S*D*atan2( psign*M[A2][A1], M[A2][A2] );
+ }
+ else if (pm > 1.0 - Math<float>::SingularityRadius)
+ { // North pole singularity
+ *a = 0.0f;
+ *b = S*D*Math<float>::PiOver2;
+ *c = S*D*atan2( psign*M[A2][A1], M[A2][A2] );
+ }
+ else
+ { // Normal case (nonsingular)
+ *a = S*D*atan2( -psign*M[A2][A3], M[A3][A3] );
+ *b = S*D*asin(pm);
+ *c = S*D*atan2( -psign*M[A1][A2], M[A1][A1] );
+ }
+
+ return;
+ }
+
+ //AnnaSteve:
+ // a,b,c, are the YawPitchRoll angles to be returned
+ // rotation a around axis A1
+ // is followed by rotation b around axis A2
+ // is followed by rotation c around axis A1
+ // rotations are CCW or CW (D) in LH or RH coordinate system (S)
+ template <Axis A1, Axis A2, RotateDirection D, HandedSystem S>
+ void ToEulerAnglesABA(float *a, float *b, float *c)
+ {
+ OVR_COMPILER_ASSERT(A1 != A2);
+
+ // Determine the axis that was not supplied
+ int m = 3 - A1 - A2;
+
+ float psign = -1.0f;
+ if ((A1 + 1) % 3 == A2) // Determine whether even permutation
+ psign = 1.0f;
+
+ float c2 = M[A1][A1];
+ if (c2 < -1.0 + Math<float>::SingularityRadius)
+ { // South pole singularity
+ *a = 0.0f;
+ *b = S*D*Math<float>::Pi;
+ *c = S*D*atan2( -psign*M[A2][m],M[A2][A2]);
+ }
+ else if (c2 > 1.0 - Math<float>::SingularityRadius)
+ { // North pole singularity
+ *a = 0.0f;
+ *b = 0.0f;
+ *c = S*D*atan2( -psign*M[A2][m],M[A2][A2]);
+ }
+ else
+ { // Normal case (nonsingular)
+ *a = S*D*atan2( M[A2][A1],-psign*M[m][A1]);
+ *b = S*D*acos(c2);
+ *c = S*D*atan2( M[A1][A2],psign*M[A1][m]);
+ }
+ return;
+ }
+
+ // Creates a matrix that converts the vertices from one coordinate system
+ // to another.
+ //
+ static Matrix4f AxisConversion(const WorldAxes& to, const WorldAxes& from)
+ {
+ // Holds axis values from the 'to' structure
+ int toArray[3] = { to.XAxis, to.YAxis, to.ZAxis };
+
+ // The inverse of the toArray
+ int inv[4];
+ inv[0] = inv[abs(to.XAxis)] = 0;
+ inv[abs(to.YAxis)] = 1;
+ inv[abs(to.ZAxis)] = 2;
+
+ Matrix4f m(0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0);
+
+ // Only three values in the matrix need to be changed to 1 or -1.
+ m.M[inv[abs(from.XAxis)]][0] = float(from.XAxis/toArray[inv[abs(from.XAxis)]]);
+ m.M[inv[abs(from.YAxis)]][1] = float(from.YAxis/toArray[inv[abs(from.YAxis)]]);
+ m.M[inv[abs(from.ZAxis)]][2] = float(from.ZAxis/toArray[inv[abs(from.ZAxis)]]);
+ return m;
+ }
+
+
+
+ static Matrix4f Translation(const Vector3f& v)
+ {
+ Matrix4f t;
+ t.M[0][3] = v.x;
+ t.M[1][3] = v.y;
+ t.M[2][3] = v.z;
+ return t;
+ }
+
+ static Matrix4f Translation(float x, float y, float z = 0.0f)
+ {
+ Matrix4f t;
+ t.M[0][3] = x;
+ t.M[1][3] = y;
+ t.M[2][3] = z;
+ return t;
+ }
+
+ static Matrix4f Scaling(const Vector3f& v)
+ {
+ Matrix4f t;
+ t.M[0][0] = v.x;
+ t.M[1][1] = v.y;
+ t.M[2][2] = v.z;
+ return t;
+ }
+
+ static Matrix4f Scaling(float x, float y, float z)
+ {
+ Matrix4f t;
+ t.M[0][0] = x;
+ t.M[1][1] = y;
+ t.M[2][2] = z;
+ return t;
+ }
+
+ static Matrix4f Scaling(float s)
+ {
+ Matrix4f t;
+ t.M[0][0] = s;
+ t.M[1][1] = s;
+ t.M[2][2] = s;
+ return t;
+ }
+
+
+
+ //AnnaSteve : Just for quick testing. Not for final API. Need to remove case.
+ static Matrix4f RotationAxis(Axis A, float angle, RotateDirection d, HandedSystem s)
+ {
+ float sina = s * d *sin(angle);
+ float cosa = cos(angle);
+
+ switch(A)
+ {
+ case Axis_X:
+ return Matrix4f(1, 0, 0,
+ 0, cosa, -sina,
+ 0, sina, cosa);
+ case Axis_Y:
+ return Matrix4f(cosa, 0, sina,
+ 0, 1, 0,
+ -sina, 0, cosa);
+ case Axis_Z:
+ return Matrix4f(cosa, -sina, 0,
+ sina, cosa, 0,
+ 0, 0, 1);
+ }
+ }
+
+
+ // Creates a rotation matrix rotating around the X axis by 'angle' radians.
+ // Rotation direction is depends on the coordinate system:
+ // RHS (Oculus default): Positive angle values rotate Counter-clockwise (CCW),
+ // while looking in the negative axis direction. This is the
+ // same as looking down from positive axis values towards origin.
+ // LHS: Positive angle values rotate clock-wise (CW), while looking in the
+ // negative axis direction.
+ static Matrix4f RotationX(float angle)
+ {
+ float sina = sin(angle);
+ float cosa = cos(angle);
+ return Matrix4f(1, 0, 0,
+ 0, cosa, -sina,
+ 0, sina, cosa);
+ }
+
+ // Creates a rotation matrix rotating around the Y axis by 'angle' radians.
+ // Rotation direction is depends on the coordinate system:
+ // RHS (Oculus default): Positive angle values rotate Counter-clockwise (CCW),
+ // while looking in the negative axis direction. This is the
+ // same as looking down from positive axis values towards origin.
+ // LHS: Positive angle values rotate clock-wise (CW), while looking in the
+ // negative axis direction.
+ static Matrix4f RotationY(float angle)
+ {
+ float sina = sin(angle);
+ float cosa = cos(angle);
+ return Matrix4f(cosa, 0, sina,
+ 0, 1, 0,
+ -sina, 0, cosa);
+ }
+
+ // Creates a rotation matrix rotating around the Z axis by 'angle' radians.
+ // Rotation direction is depends on the coordinate system:
+ // RHS (Oculus default): Positive angle values rotate Counter-clockwise (CCW),
+ // while looking in the negative axis direction. This is the
+ // same as looking down from positive axis values towards origin.
+ // LHS: Positive angle values rotate clock-wise (CW), while looking in the
+ // negative axis direction.
+ static Matrix4f RotationZ(float angle)
+ {
+ float sina = sin(angle);
+ float cosa = cos(angle);
+ return Matrix4f(cosa, -sina, 0,
+ sina, cosa, 0,
+ 0, 0, 1);
+ }
+
+
+ // LookAtRH creates a View transformation matrix for right-handed coordinate system.
+ // The resulting matrix points camera from 'eye' towards 'at' direction, with 'up'
+ // specifying the up vector. The resulting matrix should be used with PerspectiveRH
+ // projection.
+ static Matrix4f LookAtRH(const Vector3f& eye, const Vector3f& at, const Vector3f& up);
+
+ // LookAtLH creates a View transformation matrix for left-handed coordinate system.
+ // The resulting matrix points camera from 'eye' towards 'at' direction, with 'up'
+ // specifying the up vector.
+ static Matrix4f LookAtLH(const Vector3f& eye, const Vector3f& at, const Vector3f& up);
+
+
+ // PerspectiveRH creates a right-handed perspective projection matrix that can be
+ // used with the Oculus sample renderer.
+ // yfov - Specifies vertical field of view in radians.
+ // aspect - Screen aspect ration, which is usually width/height for square pixels.
+ // Note that xfov = yfov * aspect.
+ // znear - Absolute value of near Z clipping clipping range.
+ // zfar - Absolute value of far Z clipping clipping range (larger then near).
+ // Even though RHS usually looks in the direction of negative Z, positive values
+ // are expected for znear and zfar.
+ static Matrix4f PerspectiveRH(float yfov, float aspect, float znear, float zfar);
+
+
+ // PerspectiveRH creates a left-handed perspective projection matrix that can be
+ // used with the Oculus sample renderer.
+ // yfov - Specifies vertical field of view in radians.
+ // aspect - Screen aspect ration, which is usually width/height for square pixels.
+ // Note that xfov = yfov * aspect.
+ // znear - Absolute value of near Z clipping clipping range.
+ // zfar - Absolute value of far Z clipping clipping range (larger then near).
+ static Matrix4f PerspectiveLH(float yfov, float aspect, float znear, float zfar);
+
+
+ static Matrix4f Ortho2D(float w, float h);
+};
+
+
+//-------------------------------------------------------------------------------------
+// ***** Quat
+
+// Quatf represents a quaternion class used for rotations.
+//
+// Quaternion multiplications are done in right-to-left order, to match the
+// behavior of matrices.
+
+
+template<class T>
+class Quat
+{
+public:
+ // w + Xi + Yj + Zk
+ T x, y, z, w;
+
+ Quat() : x(0), y(0), z(0), w(1) {}
+ Quat(T x_, T y_, T z_, T w_) : x(x_), y(y_), z(z_), w(w_) {}
+
+
+ // Constructs rotation quaternion around the axis.
+ Quat(const Vector3<T>& axis, T angle)
+ {
+ Vector3<T> unitAxis = axis.Normalized();
+ T sinHalfAngle = sin(angle * T(0.5));
+
+ w = cos(angle * T(0.5));
+ x = unitAxis.x * sinHalfAngle;
+ y = unitAxis.y * sinHalfAngle;
+ z = unitAxis.z * sinHalfAngle;
+ }
+
+ //AnnaSteve:
+ void AxisAngle(Axis A, T angle, RotateDirection d, HandedSystem s)
+ {
+ T sinHalfAngle = s * d *sin(angle * (T)0.5);
+ T v[3];
+ v[0] = v[1] = v[2] = (T)0;
+ v[A] = sinHalfAngle;
+ //return Quat(v[0], v[1], v[2], cos(angle * (T)0.5));
+ w = cos(angle * (T)0.5);
+ x = v[0];
+ y = v[1];
+ z = v[2];
+ }
+
+
+ void GetAxisAngle(Vector3<T>* axis, T* angle) const
+ {
+ if (LengthSq() > Math<T>::Tolerance * Math<T>::Tolerance)
+ {
+ *axis = Vector3<T>(x, y, z).Normalized();
+ *angle = 2 * acos(w);
+ }
+ else
+ {
+ *axis = Vector3<T>(1, 0, 0);
+ *angle= 0;
+ }
+ }
+
+ bool operator== (const Quat& b) const { return x == b.x && y == b.y && z == b.z && w == b.w; }
+ bool operator!= (const Quat& b) const { return x != b.x || y != b.y || z != b.z || w != b.w; }
+
+ Quat operator+ (const Quat& b) const { return Quat(x + b.x, y + b.y, z + b.z, w + b.w); }
+ Quat& operator+= (const Quat& b) { w += b.w; x += b.x; y += b.y; z += b.z; return *this; }
+ Quat operator- (const Quat& b) const { return Quat(x - b.x, y - b.y, z - b.z, w - b.w); }
+ Quat& operator-= (const Quat& b) { w -= b.w; x -= b.x; y -= b.y; z -= b.z; return *this; }
+
+ Quat operator* (T s) const { return Quat(x * s, y * s, z * s, w * s); }
+ Quat& operator*= (T s) { w *= s; x *= s; y *= s; z *= s; return *this; }
+ Quat operator/ (T s) const { T rcp = T(1)/s; return Quat(x * rcp, y * rcp, z * rcp, w *rcp); }
+ Quat& operator/= (T s) { T rcp = T(1)/s; w *= rcp; x *= rcp; y *= rcp; z *= rcp; return *this; }
+
+ // Get Imaginary part vector
+ Vector3<T> Imag() const { return Vector3<T>(x,y,z); }
+
+ // Get quaternion length.
+ T Length() const { return sqrt(x * x + y * y + z * z + w * w); }
+ // Get quaternion length squared.
+ T LengthSq() const { return (x * x + y * y + z * z + w * w); }
+ // Simple Eulidean distance in R^4 (not SLERP distance, but at least respects Haar measure)
+ T Distance(const Quat& q) const
+ {
+ T d1 = (*this - q).Length();
+ T d2 = (*this + q).Length(); // Antipoldal point check
+ return (d1 < d2) ? d1 : d2;
+ }
+ T DistanceSq(const Quat& q) const
+ {
+ T d1 = (*this - q).LengthSq();
+ T d2 = (*this + q).LengthSq(); // Antipoldal point check
+ return (d1 < d2) ? d1 : d2;
+ }
+
+ // Normalize
+ bool IsNormalized() const { return fabs(LengthSq() - 1) < Math<T>::Tolerance; }
+ void Normalize() { *this /= Length(); }
+ Quat Normalized() const { return *this / Length(); }
+
+ // Returns conjugate of the quaternion. Produces inverse rotation if quaternion is normalized.
+ Quat Conj() const { return Quat(-x, -y, -z, w); }
+
+ // AnnaSteve fixed: order of quaternion multiplication
+ // Quaternion multiplication. Combines quaternion rotations, performing the one on the
+ // right hand side first.
+ Quat operator* (const Quat& b) const { return Quat(w * b.x + x * b.w + y * b.z - z * b.y,
+ w * b.y - x * b.z + y * b.w + z * b.x,
+ w * b.z + x * b.y - y * b.x + z * b.w,
+ w * b.w - x * b.x - y * b.y - z * b.z); }
+
+ //
+ // this^p normalized; same as rotating by this p times.
+ Quat PowNormalized(T p) const
+ {
+ Vector3<T> v;
+ T a;
+ GetAxisAngle(&v, &a);
+ return Quat(v, a * p);
+ }
+
+ // Rotate transforms vector in a manner that matches Matrix rotations (counter-clockwise,
+ // assuming negative direction of the axis). Standard formula: q(t) * V * q(t)^-1.
+ Vector3<T> Rotate(const Vector3<T>& v) const
+ {
+ return ((*this * Quat<T>(v.x, v.y, v.z, 0)) * Inverted()).Imag();
+ }
+
+
+ // Inversed quaternion rotates in the opposite direction.
+ Quat Inverted() const
+ {
+ return Quat(-x, -y, -z, w);
+ }
+
+ // Sets this quaternion to the one rotates in the opposite direction.
+ void Invert() const
+ {
+ *this = Quat(-x, -y, -z, w);
+ }
+
+ // Converting quaternion to matrix.
+ operator Matrix4f() const
+ {
+ T ww = w*w;
+ T xx = x*x;
+ T yy = y*y;
+ T zz = z*z;
+
+ return Matrix4f(float(ww + xx - yy - zz), float(T(2) * (x*y - w*z)), float(T(2) * (x*z + w*y)),
+ float(T(2) * (x*y + w*z)), float(ww - xx + yy - zz), float(T(2) * (y*z - w*x)),
+ float(T(2) * (x*z - w*y)), float(T(2) * (y*z + w*x)), float(ww - xx - yy + zz) );
+ }
+
+
+ // GetEulerAngles extracts Euler angles from the quaternion, in the specified order of
+ // axis rotations and the specified coordinate system. Right-handed coordinate system
+ // is the default, with CCW rotations while looking in the negative axis direction.
+ // Here a,b,c, are the Yaw/Pitch/Roll angles to be returned.
+ // rotation a around axis A1
+ // is followed by rotation b around axis A2
+ // is followed by rotation c around axis A3
+ // rotations are CCW or CW (D) in LH or RH coordinate system (S)
+ template <Axis A1, Axis A2, Axis A3, RotateDirection D, HandedSystem S>
+ void GetEulerAngles(T *a, T *b, T *c)
+ {
+ OVR_COMPILER_ASSERT((A1 != A2) && (A2 != A3) && (A1 != A3));
+
+ T Q[3] = { x, y, z }; //Quaternion components x,y,z
+
+ T ww = w*w;
+ T Q11 = Q[A1]*Q[A1];
+ T Q22 = Q[A2]*Q[A2];
+ T Q33 = Q[A3]*Q[A3];
+
+ T psign = T(-1.0);
+ // Determine whether even permutation
+ if (((A1 + 1) % 3 == A2) && ((A2 + 1) % 3 == A3))
+ psign = T(1.0);
+
+ T s2 = psign * T(2.0) * (psign*w*Q[A2] + Q[A1]*Q[A3]);
+
+ if (s2 < (T)-1.0 + Math<T>::SingularityRadius)
+ { // South pole singularity
+ *a = T(0.0);
+ *b = -S*D*Math<T>::PiOver2;
+ *c = S*D*atan2((T)2.0*(psign*Q[A1]*Q[A2] + w*Q[A3]),
+ ww + Q22 - Q11 - Q33 );
+ }
+ else if (s2 > (T)1.0 - Math<T>::SingularityRadius)
+ { // North pole singularity
+ *a = (T)0.0;
+ *b = S*D*Math<T>::PiOver2;
+ *c = S*D*atan2((T)2.0*(psign*Q[A1]*Q[A2] + w*Q[A3]),
+ ww + Q22 - Q11 - Q33);
+ }
+ else
+ {
+ *a = -S*D*atan2((T)-2.0*(w*Q[A1] - psign*Q[A2]*Q[A3]),
+ ww + Q33 - Q11 - Q22);
+ *b = S*D*asin(s2);
+ *c = S*D*atan2((T)2.0*(w*Q[A3] - psign*Q[A1]*Q[A2]),
+ ww + Q11 - Q22 - Q33);
+ }
+ return;
+ }
+
+ template <Axis A1, Axis A2, Axis A3, RotateDirection D>
+ void GetEulerAngles(T *a, T *b, T *c)
+ { GetEulerAngles<A1, A2, A3, D, Handed_R>(a, b, c); }
+
+ template <Axis A1, Axis A2, Axis A3>
+ void GetEulerAngles(T *a, T *b, T *c)
+ { GetEulerAngles<A1, A2, A3, Rotate_CCW, Handed_R>(a, b, c); }
+
+
+ // GetEulerAnglesABA extracts Euler angles from the quaternion, in the specified order of
+ // axis rotations and the specified coordinate system. Right-handed coordinate system
+ // is the default, with CCW rotations while looking in the negative axis direction.
+ // Here a,b,c, are the Yaw/Pitch/Roll angles to be returned.
+ // rotation a around axis A1
+ // is followed by rotation b around axis A2
+ // is followed by rotation c around axis A1
+ // Rotations are CCW or CW (D) in LH or RH coordinate system (S)
+ template <Axis A1, Axis A2, RotateDirection D, HandedSystem S>
+ void GetEulerAnglesABA(T *a, T *b, T *c)
+ {
+ OVR_COMPILER_ASSERT(A1 != A2);
+
+ T Q[3] = {x, y, z}; // Quaternion components
+
+ // Determine the missing axis that was not supplied
+ int m = 3 - A1 - A2;
+
+ T ww = w*w;
+ T Q11 = Q[A1]*Q[A1];
+ T Q22 = Q[A2]*Q[A2];
+ T Qmm = Q[m]*Q[m];
+
+ T psign = T(-1.0);
+ if ((A1 + 1) % 3 == A2) // Determine whether even permutation
+ {
+ psign = (T)1.0;
+ }
+
+ T c2 = ww + Q11 - Q22 - Qmm;
+ if (c2 < (T)-1.0 + Math<T>::SingularityRadius)
+ { // South pole singularity
+ *a = (T)0.0;
+ *b = S*D*Math<T>::Pi;
+ *c = S*D*atan2( (T)2.0*(w*Q[A1] - psign*Q[A2]*Q[m]),
+ ww + Q22 - Q11 - Qmm);
+ }
+ else if (c2 > (T)1.0 - Math<T>::SingularityRadius)
+ { // North pole singularity
+ *a = (T)0.0;
+ *b = (T)0.0;
+ *c = S*D*atan2( (T)2.0*(w*Q[A1] - psign*Q[A2]*Q[m]),
+ ww + Q22 - Q11 - Qmm);
+ }
+ else
+ {
+ *a = S*D*atan2( psign*w*Q[m] + Q[A1]*Q[A2],
+ w*Q[A2] -psign*Q[A1]*Q[m]);
+ *b = S*D*acos(c2);
+ *c = S*D*atan2( -psign*w*Q[m] + Q[A1]*Q[A2],
+ w*Q[A2] + psign*Q[A1]*Q[m]);
+ }
+ return;
+ }
+};
+
+
+typedef Quat<float> Quatf;
+typedef Quat<double> Quatd;
+
+
+
+//-------------------------------------------------------------------------------------
+// ***** Angle
+
+// Cleanly representing the algebra of 2D rotations.
+// The operations maintain the angle between -Pi and Pi, the same range as atan2.
+//
+
+template<class T>
+class Angle
+{
+public:
+ enum AngularUnits
+ {
+ Radians = 0,
+ Degrees = 1
+ };
+
+ Angle() : a(0) {}
+
+ // Fix the range to be between -Pi and Pi
+ Angle(T a_, AngularUnits u = Radians) : a((u == Radians) ? a_ : a_*Math<T>::DegreeToRadFactor) { FixRange(); }
+
+ T Get(AngularUnits u = Radians) const { return (u == Radians) ? a : a*Math<T>::RadToDegreeFactor; }
+ void Set(const T& x, AngularUnits u = Radians) { a = (u == Radians) ? x : x*Math<T>::DegreeToRadFactor; FixRange(); }
+ int Sign() const { if (a == 0) return 0; else return (a > 0) ? 1 : -1; }
+ T Abs() const { return (a > 0) ? a : -a; }
+
+ bool operator== (const Angle& b) const { return a == b.a; }
+ bool operator!= (const Angle& b) const { return a != b.a; }
+// bool operator< (const Angle& b) const { return a < a.b; }
+// bool operator> (const Angle& b) const { return a > a.b; }
+// bool operator<= (const Angle& b) const { return a <= a.b; }
+// bool operator>= (const Angle& b) const { return a >= a.b; }
+// bool operator= (const T& x) { a = x; FixRange(); }
+
+ // These operations assume a is already between -Pi and Pi.
+ Angle operator+ (const Angle& b) const { return Angle(a + b.a); }
+ Angle operator+ (const T& x) const { return Angle(a + x); }
+ Angle& operator+= (const Angle& b) { a = a + b.a; FastFixRange(); return *this; }
+ Angle& operator+= (const T& x) { a = a + x; FixRange(); return *this; }
+ Angle operator- (const Angle& b) const { return Angle(a - b.a); }
+ Angle operator- (const T& x) const { return Angle(a - x); }
+ Angle& operator-= (const Angle& b) { a = a - b.a; FastFixRange(); return *this; }
+ Angle& operator-= (const T& x) { a = a - x; FixRange(); return *this; }
+
+ T Distance(const Angle& b) { T c = fabs(a - b.a); return (c <= Math<T>::Pi) ? c : Math<T>::TwoPi - c; }
+
+private:
+
+ // The stored angle, which should be maintained between -Pi and Pi
+ T a;
+
+ // Fixes the angle range to [-Pi,Pi], but assumes no more than 2Pi away on either side
+ inline void FastFixRange()
+ {
+ if (a < -Math<T>::Pi)
+ a += Math<T>::TwoPi;
+ else if (a > Math<T>::Pi)
+ a -= Math<T>::TwoPi;
+ }
+
+ // Fixes the angle range to [-Pi,Pi] for any given range, but slower then the fast method
+ inline void FixRange()
+ {
+ a = fmod(a,Math<T>::TwoPi);
+ if (a < -Math<T>::Pi)
+ a += Math<T>::TwoPi;
+ else if (a > Math<T>::Pi)
+ a -= Math<T>::TwoPi;
+ }
+};
+
+
+typedef Angle<float> Anglef;
+typedef Angle<double> Angled;
+
+
+//-------------------------------------------------------------------------------------
+// ***** Plane
+
+// Consists of a normal vector and distance from the origin where the plane is located.
+
+template<class T>
+class Plane : public RefCountBase<Plane<T> >
+{
+public:
+ Vector3<T> N;
+ T D;
+
+ Plane() : D(0) {}
+
+ // Normals must already be normalized
+ Plane(const Vector3<T>& n, T d) : N(n), D(d) {}
+ Plane(T x, T y, T z, T d) : N(x,y,z), D(d) {}
+
+ // construct from a point on the plane and the normal
+ Plane(const Vector3<T>& p, const Vector3<T>& n) : N(n), D(-(p * n)) {}
+
+ // Find the point to plane distance. The sign indicates what side of the plane the point is on (0 = point on plane).
+ T TestSide(const Vector3<T>& p) const
+ {
+ return (N * p) + D;
+ }
+
+ Plane<T> Flipped() const
+ {
+ return Plane(-N, -D);
+ }
+
+ void Flip()
+ {
+ N = -N;
+ D = -D;
+ }
+
+ bool operator==(const Plane<T>& rhs) const
+ {
+ return (this->D == rhs.D && this->N == rhs.N);
+ }
+};
+
+typedef Plane<float> Planef;
+
+}
+
+#endif
diff --git a/LibOVR/Src/Kernel/OVR_RefCount.cpp b/LibOVR/Src/Kernel/OVR_RefCount.cpp
index a1171fa..aeff7ba 100644
--- a/LibOVR/Src/Kernel/OVR_RefCount.cpp
+++ b/LibOVR/Src/Kernel/OVR_RefCount.cpp
@@ -1,100 +1,100 @@
-/************************************************************************************
-
-Filename : OVR_RefCount.cpp
-Content : Reference counting implementation
-Created : September 19, 2012
-Notes :
-
-Copyright : Copyright 2012 Oculus VR, Inc. All Rights reserved.
-
-Use of this software is subject to the terms of the Oculus license
-agreement provided at the time of installation or download, or which
-otherwise accompanies this software in either electronic or hard copy form.
-
-************************************************************************************/
-
-#include "OVR_RefCount.h"
-#include "OVR_Atomic.h"
-#include "OVR_Log.h"
-
-namespace OVR {
-
-#ifdef OVR_CC_ARM
-void* ReturnArg0(void* p)
-{
- return p;
-}
-#endif
-
-// ***** Reference Count Base implementation
-
-RefCountImplCore::~RefCountImplCore()
-{
- // RefCount can be either 1 or 0 here.
- // 0 if Release() was properly called.
- // 1 if the object was declared on stack or as an aggregate.
- OVR_ASSERT(RefCount <= 1);
-}
-
-#ifdef OVR_BUILD_DEBUG
-void RefCountImplCore::reportInvalidDelete(void *pmem)
-{
- OVR_DEBUG_LOG(
- ("Invalid delete call on ref-counted object at %p. Please use Release()", pmem));
- OVR_ASSERT(0);
-}
-#endif
-
-RefCountNTSImplCore::~RefCountNTSImplCore()
-{
- // RefCount can be either 1 or 0 here.
- // 0 if Release() was properly called.
- // 1 if the object was declared on stack or as an aggregate.
- OVR_ASSERT(RefCount <= 1);
-}
-
-#ifdef OVR_BUILD_DEBUG
-void RefCountNTSImplCore::reportInvalidDelete(void *pmem)
-{
- OVR_DEBUG_LOG(
- ("Invalid delete call on ref-counted object at %p. Please use Release()", pmem));
- OVR_ASSERT(0);
-}
-#endif
-
-
-// *** Thread-Safe RefCountImpl
-
-void RefCountImpl::AddRef()
-{
- AtomicOps<int>::ExchangeAdd_NoSync(&RefCount, 1);
-}
-void RefCountImpl::Release()
-{
- if ((AtomicOps<int>::ExchangeAdd_NoSync(&RefCount, -1) - 1) == 0)
- delete this;
-}
-
-// *** Thread-Safe RefCountVImpl w/virtual AddRef/Release
-
-void RefCountVImpl::AddRef()
-{
- AtomicOps<int>::ExchangeAdd_NoSync(&RefCount, 1);
-}
-void RefCountVImpl::Release()
-{
- if ((AtomicOps<int>::ExchangeAdd_NoSync(&RefCount, -1) - 1) == 0)
- delete this;
-}
-
-// *** NON-Thread-Safe RefCountImpl
-
-void RefCountNTSImpl::Release() const
-{
- RefCount--;
- if (RefCount == 0)
- delete this;
-}
-
-
-} // OVR
+/************************************************************************************
+
+Filename : OVR_RefCount.cpp
+Content : Reference counting implementation
+Created : September 19, 2012
+Notes :
+
+Copyright : Copyright 2012 Oculus VR, Inc. All Rights reserved.
+
+Use of this software is subject to the terms of the Oculus license
+agreement provided at the time of installation or download, or which
+otherwise accompanies this software in either electronic or hard copy form.
+
+************************************************************************************/
+
+#include "OVR_RefCount.h"
+#include "OVR_Atomic.h"
+#include "OVR_Log.h"
+
+namespace OVR {
+
+#ifdef OVR_CC_ARM
+void* ReturnArg0(void* p)
+{
+ return p;
+}
+#endif
+
+// ***** Reference Count Base implementation
+
+RefCountImplCore::~RefCountImplCore()
+{
+ // RefCount can be either 1 or 0 here.
+ // 0 if Release() was properly called.
+ // 1 if the object was declared on stack or as an aggregate.
+ OVR_ASSERT(RefCount <= 1);
+}
+
+#ifdef OVR_BUILD_DEBUG
+void RefCountImplCore::reportInvalidDelete(void *pmem)
+{
+ OVR_DEBUG_LOG(
+ ("Invalid delete call on ref-counted object at %p. Please use Release()", pmem));
+ OVR_ASSERT(0);
+}
+#endif
+
+RefCountNTSImplCore::~RefCountNTSImplCore()
+{
+ // RefCount can be either 1 or 0 here.
+ // 0 if Release() was properly called.
+ // 1 if the object was declared on stack or as an aggregate.
+ OVR_ASSERT(RefCount <= 1);
+}
+
+#ifdef OVR_BUILD_DEBUG
+void RefCountNTSImplCore::reportInvalidDelete(void *pmem)
+{
+ OVR_DEBUG_LOG(
+ ("Invalid delete call on ref-counted object at %p. Please use Release()", pmem));
+ OVR_ASSERT(0);
+}
+#endif
+
+
+// *** Thread-Safe RefCountImpl
+
+void RefCountImpl::AddRef()
+{
+ AtomicOps<int>::ExchangeAdd_NoSync(&RefCount, 1);
+}
+void RefCountImpl::Release()
+{
+ if ((AtomicOps<int>::ExchangeAdd_NoSync(&RefCount, -1) - 1) == 0)
+ delete this;
+}
+
+// *** Thread-Safe RefCountVImpl w/virtual AddRef/Release
+
+void RefCountVImpl::AddRef()
+{
+ AtomicOps<int>::ExchangeAdd_NoSync(&RefCount, 1);
+}
+void RefCountVImpl::Release()
+{
+ if ((AtomicOps<int>::ExchangeAdd_NoSync(&RefCount, -1) - 1) == 0)
+ delete this;
+}
+
+// *** NON-Thread-Safe RefCountImpl
+
+void RefCountNTSImpl::Release() const
+{
+ RefCount--;
+ if (RefCount == 0)
+ delete this;
+}
+
+
+} // OVR
diff --git a/LibOVR/Src/Kernel/OVR_RefCount.h b/LibOVR/Src/Kernel/OVR_RefCount.h
index 8622050..3fae210 100644
--- a/LibOVR/Src/Kernel/OVR_RefCount.h
+++ b/LibOVR/Src/Kernel/OVR_RefCount.h
@@ -1,522 +1,522 @@
-/************************************************************************************
-
-PublicHeader: Kernel
-Filename : OVR_RefCount.h
-Content : Reference counting implementation headers
-Created : September 19, 2012
-Notes :
-
-Copyright : Copyright 2012 Oculus VR, Inc. All Rights reserved.
-
-Use of this software is subject to the terms of the Oculus license
-agreement provided at the time of installation or download, or which
-otherwise accompanies this software in either electronic or hard copy form.
-
-************************************************************************************/
-
-#ifndef OVR_RefCount_h
-#define OVR_RefCount_h
-
-#include "OVR_Types.h"
-#include "OVR_Allocator.h"
-
-namespace OVR {
-
-//-----------------------------------------------------------------------------------
-// ***** Reference Counting
-
-// There are three types of reference counting base classes:
-//
-// RefCountBase - Provides thread-safe reference counting (Default).
-// RefCountBaseNTS - Non Thread Safe version of reference counting.
-
-
-// ***** Declared classes
-
-template<class C>
-class RefCountBase;
-template<class C>
-class RefCountBaseNTS;
-
-class RefCountImpl;
-class RefCountNTSImpl;
-
-
-//-----------------------------------------------------------------------------------
-// ***** Implementation For Reference Counting
-
-// RefCountImplCore holds RefCount value and defines a few utility
-// functions shared by all implementations.
-
-class RefCountImplCore
-{
-protected:
- volatile int RefCount;
-
-public:
- // RefCountImpl constructor always initializes RefCount to 1 by default.
- OVR_FORCE_INLINE RefCountImplCore() : RefCount(1) { }
-
- // Need virtual destructor
- // This: 1. Makes sure the right destructor's called.
- // 2. Makes us have VTable, necessary if we are going to have format needed by InitNewMem()
- virtual ~RefCountImplCore();
-
- // Debug method only.
- int GetRefCount() const { return RefCount; }
-
- // This logic is used to detect invalid 'delete' calls of reference counted
- // objects. Direct delete calls are not allowed on them unless they come in
- // internally from Release.
-#ifdef OVR_BUILD_DEBUG
- static void OVR_CDECL reportInvalidDelete(void *pmem);
- inline static void checkInvalidDelete(RefCountImplCore *pmem)
- {
- if (pmem->RefCount != 0)
- reportInvalidDelete(pmem);
- }
-#else
- inline static void checkInvalidDelete(RefCountImplCore *) { }
-#endif
-
- // Base class ref-count content should not be copied.
- void operator = (const RefCountImplCore &) { }
-};
-
-class RefCountNTSImplCore
-{
-protected:
- mutable int RefCount;
-
-public:
- // RefCountImpl constructor always initializes RefCount to 1 by default.
- OVR_FORCE_INLINE RefCountNTSImplCore() : RefCount(1) { }
-
- // Need virtual destructor
- // This: 1. Makes sure the right destructor's called.
- // 2. Makes us have VTable, necessary if we are going to have format needed by InitNewMem()
- virtual ~RefCountNTSImplCore();
-
- // Debug method only.
- int GetRefCount() const { return RefCount; }
-
- // This logic is used to detect invalid 'delete' calls of reference counted
- // objects. Direct delete calls are not allowed on them unless they come in
- // internally from Release.
-#ifdef OVR_BUILD_DEBUG
- static void OVR_CDECL reportInvalidDelete(void *pmem);
- OVR_FORCE_INLINE static void checkInvalidDelete(RefCountNTSImplCore *pmem)
- {
- if (pmem->RefCount != 0)
- reportInvalidDelete(pmem);
- }
-#else
- OVR_FORCE_INLINE static void checkInvalidDelete(RefCountNTSImplCore *) { }
-#endif
-
- // Base class ref-count content should not be copied.
- void operator = (const RefCountNTSImplCore &) { }
-};
-
-
-
-// RefCountImpl provides Thread-Safe implementation of reference counting, so
-// it should be used by default in most places.
-
-class RefCountImpl : public RefCountImplCore
-{
-public:
- // Thread-Safe Ref-Count Implementation.
- void AddRef();
- void Release();
-};
-
-// RefCountVImpl provides Thread-Safe implementation of reference counting, plus,
-// virtual AddRef and Release.
-
-class RefCountVImpl : public RefCountImplCore
-{
-public:
- // Thread-Safe Ref-Count Implementation.
- virtual void AddRef();
- virtual void Release();
-};
-
-
-// RefCountImplNTS provides Non-Thread-Safe implementation of reference counting,
-// which is slightly more efficient since it doesn't use atomics.
-
-class RefCountNTSImpl : public RefCountNTSImplCore
-{
-public:
- OVR_FORCE_INLINE void AddRef() const { RefCount++; }
- void Release() const;
-};
-
-
-
-// RefCountBaseStatImpl<> is a common class that adds new/delete override with Stat tracking
-// to the reference counting implementation. Base must be one of the RefCountImpl classes.
-
-template<class Base>
-class RefCountBaseStatImpl : public Base
-{
-public:
- RefCountBaseStatImpl() { }
-
- // *** Override New and Delete
-
- // DOM-IGNORE-BEGIN
- // Undef new temporarily if it is being redefined
-#ifdef OVR_DEFINE_NEW
-#undef new
-#endif
-
-#ifdef OVR_BUILD_DEBUG
- // Custom check used to detect incorrect calls of 'delete' on ref-counted objects.
- #define OVR_REFCOUNTALLOC_CHECK_DELETE(class_name, p) \
- do {if (p) Base::checkInvalidDelete((class_name*)p); } while(0)
-#else
- #define OVR_REFCOUNTALLOC_CHECK_DELETE(class_name, p)
-#endif
-
- // Redefine all new & delete operators.
- OVR_MEMORY_REDEFINE_NEW_IMPL(Base, OVR_REFCOUNTALLOC_CHECK_DELETE)
-
-#ifdef OVR_DEFINE_NEW
-#define new OVR_DEFINE_NEW
-#endif
- // OVR_BUILD_DEFINE_NEW
- // DOM-IGNORE-END
-};
-
-
-
-//-----------------------------------------------------------------------------------
-// *** End user RefCountBase<> classes
-
-
-// RefCountBase is a base class for classes that require thread-safe reference
-// counting; it also overrides the new and delete operators to use MemoryHeap.
-//
-// Reference counted objects start out with RefCount value of 1. Further lifetime
-// management is done through the AddRef() and Release() methods, typically
-// hidden by Ptr<>.
-
-template<class C>
-class RefCountBase : public RefCountBaseStatImpl<RefCountImpl>
-{
-public:
- // Constructor.
- OVR_FORCE_INLINE RefCountBase() : RefCountBaseStatImpl<RefCountImpl>() { }
-};
-
-// RefCountBaseV is the same as RefCountBase but with virtual AddRef/Release
-
-template<class C>
-class RefCountBaseV : public RefCountBaseStatImpl<RefCountVImpl>
-{
-public:
- // Constructor.
- OVR_FORCE_INLINE RefCountBaseV() : RefCountBaseStatImpl<RefCountVImpl>() { }
-};
-
-
-// RefCountBaseNTS is a base class for classes that require Non-Thread-Safe reference
-// counting; it also overrides the new and delete operators to use MemoryHeap.
-// This class should only be used if all pointers to it are known to be assigned,
-// destroyed and manipulated within one thread.
-//
-// Reference counted objects start out with RefCount value of 1. Further lifetime
-// management is done through the AddRef() and Release() methods, typically
-// hidden by Ptr<>.
-
-template<class C>
-class RefCountBaseNTS : public RefCountBaseStatImpl<RefCountNTSImpl>
-{
-public:
- // Constructor.
- OVR_FORCE_INLINE RefCountBaseNTS() : RefCountBaseStatImpl<RefCountNTSImpl>() { }
-};
-
-//-----------------------------------------------------------------------------------
-// ***** Pickable template pointer
-enum PickType { PickValue };
-
-template <typename T>
-class Pickable
-{
-public:
- Pickable() : pV(NULL) {}
- explicit Pickable(T* p) : pV(p) {}
- Pickable(T* p, PickType) : pV(p)
- {
- OVR_ASSERT(pV);
- if (pV)
- pV->AddRef();
- }
- template <typename OT>
- Pickable(const Pickable<OT>& other) : pV(other.GetPtr()) {}
-
-public:
- Pickable& operator =(const Pickable& other)
- {
- OVR_ASSERT(pV == NULL);
- pV = other.pV;
- // Extra check.
- //other.pV = NULL;
- return *this;
- }
-
-public:
- T* GetPtr() const { return pV; }
- T* operator->() const
- {
- return pV;
- }
- T& operator*() const
- {
- OVR_ASSERT(pV);
- return *pV;
- }
-
-private:
- T* pV;
-};
-
-template <typename T>
-OVR_FORCE_INLINE
-Pickable<T> MakePickable(T* p)
-{
- return Pickable<T>(p);
-}
-
-//-----------------------------------------------------------------------------------
-// ***** Ref-Counted template pointer
-
-// Automatically AddRefs and Releases interfaces
-
-void* ReturnArg0(void* p);
-
-template<class C>
-class Ptr
-{
-#ifdef OVR_CC_ARM
- static C* ReturnArg(void* p) { return (C*)ReturnArg0(p); }
-#endif
-
-protected:
- C *pObject;
-
-public:
-
- // Constructors
- OVR_FORCE_INLINE Ptr() : pObject(0)
- { }
-#ifdef OVR_CC_ARM
- OVR_FORCE_INLINE Ptr(C &robj) : pObject(ReturnArg(&robj))
-#else
- OVR_FORCE_INLINE Ptr(C &robj) : pObject(&robj)
-#endif
- { }
- OVR_FORCE_INLINE Ptr(Pickable<C> v) : pObject(v.GetPtr())
- {
- // No AddRef() on purpose.
- }
- OVR_FORCE_INLINE Ptr(Ptr<C>& other, PickType) : pObject(other.pObject)
- {
- other.pObject = NULL;
- // No AddRef() on purpose.
- }
- OVR_FORCE_INLINE Ptr(C *pobj)
- {
- if (pobj) pobj->AddRef();
- pObject = pobj;
- }
- OVR_FORCE_INLINE Ptr(const Ptr<C> &src)
- {
- if (src.pObject) src.pObject->AddRef();
- pObject = src.pObject;
- }
-
- template<class R>
- OVR_FORCE_INLINE Ptr(Ptr<R> &src)
- {
- if (src) src->AddRef();
- pObject = src;
- }
- template<class R>
- OVR_FORCE_INLINE Ptr(Pickable<R> v) : pObject(v.GetPtr())
- {
- // No AddRef() on purpose.
- }
-
- // Destructor
- OVR_FORCE_INLINE ~Ptr()
- {
- if (pObject) pObject->Release();
- }
-
- // Compares
- OVR_FORCE_INLINE bool operator == (const Ptr &other) const { return pObject == other.pObject; }
- OVR_FORCE_INLINE bool operator != (const Ptr &other) const { return pObject != other.pObject; }
-
- OVR_FORCE_INLINE bool operator == (C *pother) const { return pObject == pother; }
- OVR_FORCE_INLINE bool operator != (C *pother) const { return pObject != pother; }
-
-
- OVR_FORCE_INLINE bool operator < (const Ptr &other) const { return pObject < other.pObject; }
-
- // Assignment
- template<class R>
- OVR_FORCE_INLINE const Ptr<C>& operator = (const Ptr<R> &src)
- {
- if (src) src->AddRef();
- if (pObject) pObject->Release();
- pObject = src;
- return *this;
- }
- // Specialization
- OVR_FORCE_INLINE const Ptr<C>& operator = (const Ptr<C> &src)
- {
- if (src) src->AddRef();
- if (pObject) pObject->Release();
- pObject = src;
- return *this;
- }
-
- OVR_FORCE_INLINE const Ptr<C>& operator = (C *psrc)
- {
- if (psrc) psrc->AddRef();
- if (pObject) pObject->Release();
- pObject = psrc;
- return *this;
- }
- OVR_FORCE_INLINE const Ptr<C>& operator = (C &src)
- {
- if (pObject) pObject->Release();
- pObject = &src;
- return *this;
- }
- OVR_FORCE_INLINE Ptr<C>& operator = (Pickable<C> src)
- {
- return Pick(src);
- }
- template<class R>
- OVR_FORCE_INLINE Ptr<C>& operator = (Pickable<R> src)
- {
- return Pick(src);
- }
-
- // Set Assignment
- template<class R>
- OVR_FORCE_INLINE Ptr<C>& SetPtr(const Ptr<R> &src)
- {
- if (src) src->AddRef();
- if (pObject) pObject->Release();
- pObject = src;
- return *this;
- }
- // Specialization
- OVR_FORCE_INLINE Ptr<C>& SetPtr(const Ptr<C> &src)
- {
- if (src) src->AddRef();
- if (pObject) pObject->Release();
- pObject = src;
- return *this;
- }
-
- OVR_FORCE_INLINE Ptr<C>& SetPtr(C *psrc)
- {
- if (psrc) psrc->AddRef();
- if (pObject) pObject->Release();
- pObject = psrc;
- return *this;
- }
- OVR_FORCE_INLINE Ptr<C>& SetPtr(C &src)
- {
- if (pObject) pObject->Release();
- pObject = &src;
- return *this;
- }
- OVR_FORCE_INLINE Ptr<C>& SetPtr(Pickable<C> src)
- {
- return Pick(src);
- }
-
- // Nulls ref-counted pointer without decrement
- OVR_FORCE_INLINE void NullWithoutRelease()
- {
- pObject = 0;
- }
-
- // Clears the pointer to the object
- OVR_FORCE_INLINE void Clear()
- {
- if (pObject) pObject->Release();
- pObject = 0;
- }
-
- // Obtain pointer reference directly, for D3D interfaces
- OVR_FORCE_INLINE C*& GetRawRef() { return pObject; }
-
- // Access Operators
- OVR_FORCE_INLINE C* GetPtr() const { return pObject; }
- OVR_FORCE_INLINE C& operator * () const { return *pObject; }
- OVR_FORCE_INLINE C* operator -> () const { return pObject; }
- // Conversion
- OVR_FORCE_INLINE operator C* () const { return pObject; }
-
- // Pickers.
-
- // Pick a value.
- OVR_FORCE_INLINE Ptr<C>& Pick(Ptr<C>& other)
- {
- if (&other != this)
- {
- if (pObject) pObject->Release();
- pObject = other.pObject;
- other.pObject = 0;
- }
-
- return *this;
- }
-
- OVR_FORCE_INLINE Ptr<C>& Pick(Pickable<C> v)
- {
- if (v.GetPtr() != pObject)
- {
- if (pObject) pObject->Release();
- pObject = v.GetPtr();
- }
-
- return *this;
- }
-
- template<class R>
- OVR_FORCE_INLINE Ptr<C>& Pick(Pickable<R> v)
- {
- if (v.GetPtr() != pObject)
- {
- if (pObject) pObject->Release();
- pObject = v.GetPtr();
- }
-
- return *this;
- }
-
- OVR_FORCE_INLINE Ptr<C>& Pick(C* p)
- {
- if (p != pObject)
- {
- if (pObject) pObject->Release();
- pObject = p;
- }
-
- return *this;
- }
-};
-
-} // OVR
-
-#endif
+/************************************************************************************
+
+PublicHeader: Kernel
+Filename : OVR_RefCount.h
+Content : Reference counting implementation headers
+Created : September 19, 2012
+Notes :
+
+Copyright : Copyright 2012 Oculus VR, Inc. All Rights reserved.
+
+Use of this software is subject to the terms of the Oculus license
+agreement provided at the time of installation or download, or which
+otherwise accompanies this software in either electronic or hard copy form.
+
+************************************************************************************/
+
+#ifndef OVR_RefCount_h
+#define OVR_RefCount_h
+
+#include "OVR_Types.h"
+#include "OVR_Allocator.h"
+
+namespace OVR {
+
+//-----------------------------------------------------------------------------------
+// ***** Reference Counting
+
+// There are three types of reference counting base classes:
+//
+// RefCountBase - Provides thread-safe reference counting (Default).
+// RefCountBaseNTS - Non Thread Safe version of reference counting.
+
+
+// ***** Declared classes
+
+template<class C>
+class RefCountBase;
+template<class C>
+class RefCountBaseNTS;
+
+class RefCountImpl;
+class RefCountNTSImpl;
+
+
+//-----------------------------------------------------------------------------------
+// ***** Implementation For Reference Counting
+
+// RefCountImplCore holds RefCount value and defines a few utility
+// functions shared by all implementations.
+
+class RefCountImplCore
+{
+protected:
+ volatile int RefCount;
+
+public:
+ // RefCountImpl constructor always initializes RefCount to 1 by default.
+ OVR_FORCE_INLINE RefCountImplCore() : RefCount(1) { }
+
+ // Need virtual destructor
+ // This: 1. Makes sure the right destructor's called.
+ // 2. Makes us have VTable, necessary if we are going to have format needed by InitNewMem()
+ virtual ~RefCountImplCore();
+
+ // Debug method only.
+ int GetRefCount() const { return RefCount; }
+
+ // This logic is used to detect invalid 'delete' calls of reference counted
+ // objects. Direct delete calls are not allowed on them unless they come in
+ // internally from Release.
+#ifdef OVR_BUILD_DEBUG
+ static void OVR_CDECL reportInvalidDelete(void *pmem);
+ inline static void checkInvalidDelete(RefCountImplCore *pmem)
+ {
+ if (pmem->RefCount != 0)
+ reportInvalidDelete(pmem);
+ }
+#else
+ inline static void checkInvalidDelete(RefCountImplCore *) { }
+#endif
+
+ // Base class ref-count content should not be copied.
+ void operator = (const RefCountImplCore &) { }
+};
+
+class RefCountNTSImplCore
+{
+protected:
+ mutable int RefCount;
+
+public:
+ // RefCountImpl constructor always initializes RefCount to 1 by default.
+ OVR_FORCE_INLINE RefCountNTSImplCore() : RefCount(1) { }
+
+ // Need virtual destructor
+ // This: 1. Makes sure the right destructor's called.
+ // 2. Makes us have VTable, necessary if we are going to have format needed by InitNewMem()
+ virtual ~RefCountNTSImplCore();
+
+ // Debug method only.
+ int GetRefCount() const { return RefCount; }
+
+ // This logic is used to detect invalid 'delete' calls of reference counted
+ // objects. Direct delete calls are not allowed on them unless they come in
+ // internally from Release.
+#ifdef OVR_BUILD_DEBUG
+ static void OVR_CDECL reportInvalidDelete(void *pmem);
+ OVR_FORCE_INLINE static void checkInvalidDelete(RefCountNTSImplCore *pmem)
+ {
+ if (pmem->RefCount != 0)
+ reportInvalidDelete(pmem);
+ }
+#else
+ OVR_FORCE_INLINE static void checkInvalidDelete(RefCountNTSImplCore *) { }
+#endif
+
+ // Base class ref-count content should not be copied.
+ void operator = (const RefCountNTSImplCore &) { }
+};
+
+
+
+// RefCountImpl provides Thread-Safe implementation of reference counting, so
+// it should be used by default in most places.
+
+class RefCountImpl : public RefCountImplCore
+{
+public:
+ // Thread-Safe Ref-Count Implementation.
+ void AddRef();
+ void Release();
+};
+
+// RefCountVImpl provides Thread-Safe implementation of reference counting, plus,
+// virtual AddRef and Release.
+
+class RefCountVImpl : public RefCountImplCore
+{
+public:
+ // Thread-Safe Ref-Count Implementation.
+ virtual void AddRef();
+ virtual void Release();
+};
+
+
+// RefCountImplNTS provides Non-Thread-Safe implementation of reference counting,
+// which is slightly more efficient since it doesn't use atomics.
+
+class RefCountNTSImpl : public RefCountNTSImplCore
+{
+public:
+ OVR_FORCE_INLINE void AddRef() const { RefCount++; }
+ void Release() const;
+};
+
+
+
+// RefCountBaseStatImpl<> is a common class that adds new/delete override with Stat tracking
+// to the reference counting implementation. Base must be one of the RefCountImpl classes.
+
+template<class Base>
+class RefCountBaseStatImpl : public Base
+{
+public:
+ RefCountBaseStatImpl() { }
+
+ // *** Override New and Delete
+
+ // DOM-IGNORE-BEGIN
+ // Undef new temporarily if it is being redefined
+#ifdef OVR_DEFINE_NEW
+#undef new
+#endif
+
+#ifdef OVR_BUILD_DEBUG
+ // Custom check used to detect incorrect calls of 'delete' on ref-counted objects.
+ #define OVR_REFCOUNTALLOC_CHECK_DELETE(class_name, p) \
+ do {if (p) Base::checkInvalidDelete((class_name*)p); } while(0)
+#else
+ #define OVR_REFCOUNTALLOC_CHECK_DELETE(class_name, p)
+#endif
+
+ // Redefine all new & delete operators.
+ OVR_MEMORY_REDEFINE_NEW_IMPL(Base, OVR_REFCOUNTALLOC_CHECK_DELETE)
+
+#ifdef OVR_DEFINE_NEW
+#define new OVR_DEFINE_NEW
+#endif
+ // OVR_BUILD_DEFINE_NEW
+ // DOM-IGNORE-END
+};
+
+
+
+//-----------------------------------------------------------------------------------
+// *** End user RefCountBase<> classes
+
+
+// RefCountBase is a base class for classes that require thread-safe reference
+// counting; it also overrides the new and delete operators to use MemoryHeap.
+//
+// Reference counted objects start out with RefCount value of 1. Further lifetime
+// management is done through the AddRef() and Release() methods, typically
+// hidden by Ptr<>.
+
+template<class C>
+class RefCountBase : public RefCountBaseStatImpl<RefCountImpl>
+{
+public:
+ // Constructor.
+ OVR_FORCE_INLINE RefCountBase() : RefCountBaseStatImpl<RefCountImpl>() { }
+};
+
+// RefCountBaseV is the same as RefCountBase but with virtual AddRef/Release
+
+template<class C>
+class RefCountBaseV : public RefCountBaseStatImpl<RefCountVImpl>
+{
+public:
+ // Constructor.
+ OVR_FORCE_INLINE RefCountBaseV() : RefCountBaseStatImpl<RefCountVImpl>() { }
+};
+
+
+// RefCountBaseNTS is a base class for classes that require Non-Thread-Safe reference
+// counting; it also overrides the new and delete operators to use MemoryHeap.
+// This class should only be used if all pointers to it are known to be assigned,
+// destroyed and manipulated within one thread.
+//
+// Reference counted objects start out with RefCount value of 1. Further lifetime
+// management is done through the AddRef() and Release() methods, typically
+// hidden by Ptr<>.
+
+template<class C>
+class RefCountBaseNTS : public RefCountBaseStatImpl<RefCountNTSImpl>
+{
+public:
+ // Constructor.
+ OVR_FORCE_INLINE RefCountBaseNTS() : RefCountBaseStatImpl<RefCountNTSImpl>() { }
+};
+
+//-----------------------------------------------------------------------------------
+// ***** Pickable template pointer
+enum PickType { PickValue };
+
+template <typename T>
+class Pickable
+{
+public:
+ Pickable() : pV(NULL) {}
+ explicit Pickable(T* p) : pV(p) {}
+ Pickable(T* p, PickType) : pV(p)
+ {
+ OVR_ASSERT(pV);
+ if (pV)
+ pV->AddRef();
+ }
+ template <typename OT>
+ Pickable(const Pickable<OT>& other) : pV(other.GetPtr()) {}
+
+public:
+ Pickable& operator =(const Pickable& other)
+ {
+ OVR_ASSERT(pV == NULL);
+ pV = other.pV;
+ // Extra check.
+ //other.pV = NULL;
+ return *this;
+ }
+
+public:
+ T* GetPtr() const { return pV; }
+ T* operator->() const
+ {
+ return pV;
+ }
+ T& operator*() const
+ {
+ OVR_ASSERT(pV);
+ return *pV;
+ }
+
+private:
+ T* pV;
+};
+
+template <typename T>
+OVR_FORCE_INLINE
+Pickable<T> MakePickable(T* p)
+{
+ return Pickable<T>(p);
+}
+
+//-----------------------------------------------------------------------------------
+// ***** Ref-Counted template pointer
+
+// Automatically AddRefs and Releases interfaces
+
+void* ReturnArg0(void* p);
+
+template<class C>
+class Ptr
+{
+#ifdef OVR_CC_ARM
+ static C* ReturnArg(void* p) { return (C*)ReturnArg0(p); }
+#endif
+
+protected:
+ C *pObject;
+
+public:
+
+ // Constructors
+ OVR_FORCE_INLINE Ptr() : pObject(0)
+ { }
+#ifdef OVR_CC_ARM
+ OVR_FORCE_INLINE Ptr(C &robj) : pObject(ReturnArg(&robj))
+#else
+ OVR_FORCE_INLINE Ptr(C &robj) : pObject(&robj)
+#endif
+ { }
+ OVR_FORCE_INLINE Ptr(Pickable<C> v) : pObject(v.GetPtr())
+ {
+ // No AddRef() on purpose.
+ }
+ OVR_FORCE_INLINE Ptr(Ptr<C>& other, PickType) : pObject(other.pObject)
+ {
+ other.pObject = NULL;
+ // No AddRef() on purpose.
+ }
+ OVR_FORCE_INLINE Ptr(C *pobj)
+ {
+ if (pobj) pobj->AddRef();
+ pObject = pobj;
+ }
+ OVR_FORCE_INLINE Ptr(const Ptr<C> &src)
+ {
+ if (src.pObject) src.pObject->AddRef();
+ pObject = src.pObject;
+ }
+
+ template<class R>
+ OVR_FORCE_INLINE Ptr(Ptr<R> &src)
+ {
+ if (src) src->AddRef();
+ pObject = src;
+ }
+ template<class R>
+ OVR_FORCE_INLINE Ptr(Pickable<R> v) : pObject(v.GetPtr())
+ {
+ // No AddRef() on purpose.
+ }
+
+ // Destructor
+ OVR_FORCE_INLINE ~Ptr()
+ {
+ if (pObject) pObject->Release();
+ }
+
+ // Compares
+ OVR_FORCE_INLINE bool operator == (const Ptr &other) const { return pObject == other.pObject; }
+ OVR_FORCE_INLINE bool operator != (const Ptr &other) const { return pObject != other.pObject; }
+
+ OVR_FORCE_INLINE bool operator == (C *pother) const { return pObject == pother; }
+ OVR_FORCE_INLINE bool operator != (C *pother) const { return pObject != pother; }
+
+
+ OVR_FORCE_INLINE bool operator < (const Ptr &other) const { return pObject < other.pObject; }
+
+ // Assignment
+ template<class R>
+ OVR_FORCE_INLINE const Ptr<C>& operator = (const Ptr<R> &src)
+ {
+ if (src) src->AddRef();
+ if (pObject) pObject->Release();
+ pObject = src;
+ return *this;
+ }
+ // Specialization
+ OVR_FORCE_INLINE const Ptr<C>& operator = (const Ptr<C> &src)
+ {
+ if (src) src->AddRef();
+ if (pObject) pObject->Release();
+ pObject = src;
+ return *this;
+ }
+
+ OVR_FORCE_INLINE const Ptr<C>& operator = (C *psrc)
+ {
+ if (psrc) psrc->AddRef();
+ if (pObject) pObject->Release();
+ pObject = psrc;
+ return *this;
+ }
+ OVR_FORCE_INLINE const Ptr<C>& operator = (C &src)
+ {
+ if (pObject) pObject->Release();
+ pObject = &src;
+ return *this;
+ }
+ OVR_FORCE_INLINE Ptr<C>& operator = (Pickable<C> src)
+ {
+ return Pick(src);
+ }
+ template<class R>
+ OVR_FORCE_INLINE Ptr<C>& operator = (Pickable<R> src)
+ {
+ return Pick(src);
+ }
+
+ // Set Assignment
+ template<class R>
+ OVR_FORCE_INLINE Ptr<C>& SetPtr(const Ptr<R> &src)
+ {
+ if (src) src->AddRef();
+ if (pObject) pObject->Release();
+ pObject = src;
+ return *this;
+ }
+ // Specialization
+ OVR_FORCE_INLINE Ptr<C>& SetPtr(const Ptr<C> &src)
+ {
+ if (src) src->AddRef();
+ if (pObject) pObject->Release();
+ pObject = src;
+ return *this;
+ }
+
+ OVR_FORCE_INLINE Ptr<C>& SetPtr(C *psrc)
+ {
+ if (psrc) psrc->AddRef();
+ if (pObject) pObject->Release();
+ pObject = psrc;
+ return *this;
+ }
+ OVR_FORCE_INLINE Ptr<C>& SetPtr(C &src)
+ {
+ if (pObject) pObject->Release();
+ pObject = &src;
+ return *this;
+ }
+ OVR_FORCE_INLINE Ptr<C>& SetPtr(Pickable<C> src)
+ {
+ return Pick(src);
+ }
+
+ // Nulls ref-counted pointer without decrement
+ OVR_FORCE_INLINE void NullWithoutRelease()
+ {
+ pObject = 0;
+ }
+
+ // Clears the pointer to the object
+ OVR_FORCE_INLINE void Clear()
+ {
+ if (pObject) pObject->Release();
+ pObject = 0;
+ }
+
+ // Obtain pointer reference directly, for D3D interfaces
+ OVR_FORCE_INLINE C*& GetRawRef() { return pObject; }
+
+ // Access Operators
+ OVR_FORCE_INLINE C* GetPtr() const { return pObject; }
+ OVR_FORCE_INLINE C& operator * () const { return *pObject; }
+ OVR_FORCE_INLINE C* operator -> () const { return pObject; }
+ // Conversion
+ OVR_FORCE_INLINE operator C* () const { return pObject; }
+
+ // Pickers.
+
+ // Pick a value.
+ OVR_FORCE_INLINE Ptr<C>& Pick(Ptr<C>& other)
+ {
+ if (&other != this)
+ {
+ if (pObject) pObject->Release();
+ pObject = other.pObject;
+ other.pObject = 0;
+ }
+
+ return *this;
+ }
+
+ OVR_FORCE_INLINE Ptr<C>& Pick(Pickable<C> v)
+ {
+ if (v.GetPtr() != pObject)
+ {
+ if (pObject) pObject->Release();
+ pObject = v.GetPtr();
+ }
+
+ return *this;
+ }
+
+ template<class R>
+ OVR_FORCE_INLINE Ptr<C>& Pick(Pickable<R> v)
+ {
+ if (v.GetPtr() != pObject)
+ {
+ if (pObject) pObject->Release();
+ pObject = v.GetPtr();
+ }
+
+ return *this;
+ }
+
+ OVR_FORCE_INLINE Ptr<C>& Pick(C* p)
+ {
+ if (p != pObject)
+ {
+ if (pObject) pObject->Release();
+ pObject = p;
+ }
+
+ return *this;
+ }
+};
+
+} // OVR
+
+#endif
diff --git a/LibOVR/Src/Kernel/OVR_Std.cpp b/LibOVR/Src/Kernel/OVR_Std.cpp
index 088f9e9..d6043ab 100644
--- a/LibOVR/Src/Kernel/OVR_Std.cpp
+++ b/LibOVR/Src/Kernel/OVR_Std.cpp
@@ -1,1025 +1,1025 @@
-/************************************************************************************
-
-Filename : OVR_Std.cpp
-Content : Standard C function implementation
-Created : September 19, 2012
-Notes :
-
-Copyright : Copyright 2012 Oculus VR, Inc. All Rights reserved.
-
-Use of this software is subject to the terms of the Oculus license
-agreement provided at the time of installation or download, or which
-otherwise accompanies this software in either electronic or hard copy form.
-
-************************************************************************************/
-
-#include "OVR_Std.h"
-#include "OVR_Alg.h"
-
-// localeconv() call in OVR_strtod()
-#include <locale.h>
-
-namespace OVR {
-
-// Source for functions not available on all platforms is included here.
-
-// Case insensitive compare implemented in platform-specific way.
-int OVR_CDECL OVR_stricmp(const char* a, const char* b)
-{
-#if defined(OVR_OS_WIN32)
- #if defined(OVR_CC_MSVC) && (OVR_CC_MSVC >= 1400)
- return ::_stricmp(a, b);
- #else
- return ::stricmp(a, b);
- #endif
-
-#else
- return strcasecmp(a, b);
-#endif
-}
-
-int OVR_CDECL OVR_strnicmp(const char* a, const char* b, UPInt count)
-{
-#if defined(OVR_OS_WIN32)
-#if defined(OVR_CC_MSVC) && (OVR_CC_MSVC >= 1400)
- return ::_strnicmp(a, b, count);
-#else
- return ::strnicmp(a, b, count);
-#endif
-
-#else
- return strncasecmp(a, b, count);
-#endif
-}
-
-wchar_t* OVR_CDECL OVR_wcscpy(wchar_t* dest, UPInt destsize, const wchar_t* src)
-{
-#if defined(OVR_MSVC_SAFESTRING)
- wcscpy_s(dest, destsize, src);
- return dest;
-#elif defined(OVR_OS_WIN32)
- OVR_UNUSED(destsize);
- wcscpy(dest, src);
- return dest;
-#else
- UPInt l = OVR_wcslen(src) + 1; // incl term null
- l = (l < destsize) ? l : destsize;
- memcpy(dest, src, l * sizeof(wchar_t));
- return dest;
-#endif
-}
-
-wchar_t* OVR_CDECL OVR_wcsncpy(wchar_t* dest, UPInt destsize, const wchar_t* src, UPInt count)
-{
-#if defined(OVR_MSVC_SAFESTRING)
- wcsncpy_s(dest, destsize, src, count);
- return dest;
-#else
- UPInt srclen = OVR_wcslen(src);
- UPInt l = Alg::Min(srclen, count);
- l = (l < destsize) ? l : destsize;
- memcpy(dest, src, l * sizeof(wchar_t));
- if (count > srclen)
- {
- UPInt remLen = Alg::Min(destsize - l, (count - srclen));
- memset(&dest[l], 0, sizeof(wchar_t)*remLen);
- }
- else if (l < destsize)
- dest[l] = 0;
- return dest;
-#endif
-}
-
-
-wchar_t* OVR_CDECL OVR_wcscat(wchar_t* dest, UPInt destsize, const wchar_t* src)
-{
-#if defined(OVR_MSVC_SAFESTRING)
- wcscat_s(dest, destsize, src);
- return dest;
-#elif defined(OVR_OS_WIN32)
- OVR_UNUSED(destsize);
- wcscat(dest, src);
- return dest;
-#else
- UPInt dstlen = OVR_wcslen(dest); // do not incl term null
- UPInt srclen = OVR_wcslen(src) + 1; // incl term null
- UPInt copylen = (dstlen + srclen < destsize) ? srclen : destsize - dstlen;
- memcpy(dest + dstlen, src, copylen * sizeof(wchar_t));
- return dest;
-#endif
-}
-
-UPInt OVR_CDECL OVR_wcslen(const wchar_t* str)
-{
-#if defined(OVR_OS_WIN32)
- return wcslen(str);
-#else
- UPInt i = 0;
- while(str[i] != '\0')
- ++i;
- return i;
-#endif
-}
-
-int OVR_CDECL OVR_wcscmp(const wchar_t* a, const wchar_t* b)
-{
-#if defined(OVR_OS_WIN32) || defined(OVR_OS_LINUX)
- return wcscmp(a, b);
-#else
- // not supported, use custom implementation
- const wchar_t *pa = a, *pb = b;
- while (*pa && *pb)
- {
- wchar_t ca = *pa;
- wchar_t cb = *pb;
- if (ca < cb)
- return -1;
- else if (ca > cb)
- return 1;
- pa++;
- pb++;
- }
- if (*pa)
- return 1;
- else if (*pb)
- return -1;
- else
- return 0;
-#endif
-}
-
-int OVR_CDECL OVR_wcsicmp(const wchar_t* a, const wchar_t* b)
-{
-#if defined(OVR_OS_WIN32)
-#if defined(OVR_CC_MSVC) && (OVR_CC_MSVC >= 1400)
- return ::_wcsicmp(a, b);
-#else
- return ::wcsicmp(a, b);
-#endif
-#elif defined(OVR_OS_MAC) || defined(__CYGWIN__) || defined(OVR_OS_ANDROID) || defined(OVR_OS_IPHONE)
- // not supported, use custom implementation
- const wchar_t *pa = a, *pb = b;
- while (*pa && *pb)
- {
- wchar_t ca = OVR_towlower(*pa);
- wchar_t cb = OVR_towlower(*pb);
- if (ca < cb)
- return -1;
- else if (ca > cb)
- return 1;
- pa++;
- pb++;
- }
- if (*pa)
- return 1;
- else if (*pb)
- return -1;
- else
- return 0;
-#else
- return wcscasecmp(a, b);
-#endif
-}
-
-// This function is not inline because of dependency on <locale.h>
-double OVR_CDECL OVR_strtod(const char* string, char** tailptr)
-{
-#if !defined(OVR_OS_ANDROID)
- const char s = *localeconv()->decimal_point;
-
- if (s != '.')
- {
- char buffer[347 + 1];
-
- OVR_strcpy(buffer, sizeof(buffer), string);
-
- for (char* c = buffer; *c != '\0'; ++c)
- {
- if (*c == '.')
- {
- *c = s;
- break;
- }
- }
-
- return strtod(buffer, tailptr);
- }
-#endif
-
- return strtod(string, tailptr);
-}
-
-
-#ifndef OVR_NO_WCTYPE
-
-//// Use this class to generate Unicode bitsets. For example:
-////
-//// UnicodeBitSet bitSet;
-//// for(unsigned i = 0; i < 65536; ++i)
-//// {
-//// if (iswalpha(i))
-//// bitSet.Set(i);
-//// }
-//// bitSet.Dump();
-////
-////---------------------------------------------------------------
-//class UnicodeBitSet
-//{
-//public:
-// UnicodeBitSet()
-// {
-// memset(Offsets, 0, sizeof(Offsets));
-// memset(Bits, 0, sizeof(Bits));
-// }
-//
-// void Set(unsigned bit) { Bits[bit >> 8][(bit >> 4) & 15] |= 1 << (bit & 15); }
-//
-// void Dump()
-// {
-// unsigned i, j;
-// unsigned offsetCount = 0;
-// for(i = 0; i < 256; ++i)
-// {
-// if (isNull(i)) Offsets[i] = 0;
-// else
-// if (isFull(i)) Offsets[i] = 1;
-// else Offsets[i] = UInt16(offsetCount++ * 16 + 256);
-// }
-// for(i = 0; i < 16; ++i)
-// {
-// for(j = 0; j < 16; ++j)
-// {
-// printf("%5u,", Offsets[i*16+j]);
-// }
-// printf("\n");
-// }
-// for(i = 0; i < 256; ++i)
-// {
-// if (Offsets[i] > 255)
-// {
-// for(j = 0; j < 16; j++)
-// {
-// printf("%5u,", Bits[i][j]);
-// }
-// printf("\n");
-// }
-// }
-// }
-//
-//private:
-// bool isNull(unsigned n) const
-// {
-// const UInt16* p = Bits[n];
-// for(unsigned i = 0; i < 16; ++i)
-// if (p[i] != 0) return false;
-// return true;
-// }
-//
-// bool isFull(unsigned n) const
-// {
-// const UInt16* p = Bits[n];
-// for(unsigned i = 0; i < 16; ++i)
-// if (p[i] != 0xFFFF) return false;
-// return true;
-// }
-//
-// UInt16 Offsets[256];
-// UInt16 Bits[256][16];
-//};
-
-
-const UInt16 UnicodeAlnumBits[] = {
- 256, 1, 272, 288, 304, 320, 336, 352, 0, 368, 384, 400, 416, 432, 448, 464,
- 480, 496, 512, 528, 544, 1, 560, 576, 592, 0, 0, 0, 0, 0, 608, 624,
- 640, 656, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 672, 688, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 704, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 720,
- 1, 1, 1, 1, 736, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 752, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 768, 784, 1, 800, 816, 832,
- 0, 0, 0, 1023,65534, 2047,65534, 2047, 0, 0, 0, 524,65535,65407,65535,65407,
-65535,65535,65532, 15, 0,65535,65535,65535,65535,65535,16383,63999, 3, 0,16415, 0,
- 0, 0, 0, 0, 32, 0, 0, 1024,55104,65535,65531,65535,32767,64767,65535, 15,
-65535,65535,65535,65535,65535,65535,65535,65535,61443,65535,65535,65535, 6559,65535,65535, 831,
- 0, 0, 0,65534,65535, 639,65534,65535, 255, 0, 0, 0, 0,65535, 2047, 7,
- 0, 0,65534, 2047,65534, 63, 1023,65535,65535,65535,65535,65535,65535, 8175, 8702, 8191,
- 0,65535, 8191,65535, 0, 0, 0, 0,65535,65535,65535, 1, 0, 0, 0, 0,
-65518,65535,65535,58367, 8191,65281,65487, 0,40942,65529,65023,50117, 6559,45184,65487, 3,
-34788,65529,65023,50029, 6535,24064,65472, 31,45038,65531,65023,58349, 7103, 1,65473, 0,
-40942,65529,65023,58317, 6543,45248,65475, 0,51180,54845,50968,50111, 7623, 128,65408, 0,
-57326,65533,65023,50159, 7647, 96,65475, 0,57324,65533,65023,50159, 7647,16480,65475, 0,
-57324,65533,65023,50175, 7631, 128,65475, 0,65516,64639,65535,12283,32895,65375, 0, 12,
-65534,65535,65535, 2047,32767, 1023, 0, 0, 9622,65264,60590,15359, 8223,13311, 0, 0,
- 1, 0, 1023, 0,65279,65535, 2047,65534, 3843,65279,65535, 8191, 0, 0, 0, 0,
-65535,65535,63227, 327, 1023, 1023, 0, 0, 0, 0,65535,65535, 63,65535,65535, 127,
-65535,65535,65535,65535,65535,33791,65535,65535,65535,65535,65287,65535,65535,65535,65535, 1023,
-65407,65535,65535,65535,15743,15743,65535,65535,15743,65535,32767,32573,32573,65407,32767,65535,
-32767,32573,65535,65535,65407, 2047,65024, 3, 0, 0,65535,65535,65535,65535,65535, 31,
-65534,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,
-65535,65535,65535,65535,65535,65535,40959, 127,65534, 2047,65535,65535,65535,65535, 2047, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,65535,65535,65535,65535, 511, 0, 1023, 0,
- 0, 1023,65535,65535,65527,65535,65535, 255,65535,65535, 1023, 0, 0, 0, 0, 0,
-65535,65535,65535,65535,65535,65535,65535,65535,65535, 4095,65535,65535,65535,65535,65535, 1023,
-65535,16191,65535,65535,16191,43775,65535,16383,65535,65535,65535,24543, 8156, 4047, 8191, 8156,
- 0, 0, 0, 0, 0, 0, 0,32768, 0, 0, 0, 0, 0, 0, 0, 0,
-64644,15919,48464, 1019, 0, 0,65535,65535, 15, 0, 0, 0, 0, 0, 0, 0,
- 192, 0, 1022, 1792,65534,65535,65535,65535,65535, 31,65534,65535,65535,65535,65535, 2047,
-65504,65535, 8191,65534,65535,65535,65535,65535,32767, 0,65535, 255, 0, 0, 0, 0,
-65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535, 63, 0, 0, 0, 0,
-65535,65535,65535,65535,65535,65535,65535,65535,65535,65535, 63, 0, 0, 0, 0, 0,
-65535,65535,65535,65535,65535,65535,65535,65535, 8191, 0, 0, 0, 0, 0, 0, 0,
-65535,65535,65535,65535,65535,65535,65535,65535,65535,65535, 15, 0, 0, 0, 0, 0,
-65535,65535,16383, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 127,41208,65023,24447,65499,65535,65535,65535,65535,65535,65535, 3, 0,65528,65535,65535,
-65535,65535,65535,16383, 0,65535,65535,65535,65535,65532,65535,65535, 255, 0, 0, 4095,
- 0, 0, 0, 0, 0, 0, 0,65495,65535,65535,65535,65535,65535,65535,65535, 8191,
- 0, 1023,65534, 2047,65534, 2047,65472,65534,65535,16383,65535,32767,64764, 7420, 0, 0};
-
-const UInt16 UnicodeAlphaBits[] = {
- 256, 1, 272, 288, 304, 320, 336, 352, 0, 368, 384, 400, 416, 432, 448, 464,
- 480, 496, 512, 528, 544, 1, 560, 576, 592, 0, 0, 0, 0, 0, 608, 624,
- 640, 656, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 672, 688, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 704, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 720,
- 1, 1, 1, 1, 736, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 752, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 768, 784, 1, 800, 816, 832,
- 0, 0, 0, 0,65534, 2047,65534, 2047, 0, 0, 0, 0,65535,65407,65535,65407,
-65535,65535,65532, 15, 0,65535,65535,65535,65535,65535,16383,63999, 3, 0,16415, 0,
- 0, 0, 0, 0, 32, 0, 0, 1024,55104,65535,65531,65535,32767,64767,65535, 15,
-65535,65535,65535,65535,65535,65535,65535,65535,61443,65535,65535,65535, 6559,65535,65535, 831,
- 0, 0, 0,65534,65535, 639,65534,65535, 255, 0, 0, 0, 0,65535, 2047, 7,
- 0, 0,65534, 2047,65534, 63, 0,65535,65535,65535,65535,65535,65535, 8175, 8702, 7168,
- 0,65535, 8191,65535, 0, 0, 0, 0,65535,65535,65535, 1, 0, 0, 0, 0,
-65518,65535,65535,58367, 8191,65281, 15, 0,40942,65529,65023,50117, 6559,45184, 15, 3,
-34788,65529,65023,50029, 6535,24064, 0, 31,45038,65531,65023,58349, 7103, 1, 1, 0,
-40942,65529,65023,58317, 6543,45248, 3, 0,51180,54845,50968,50111, 7623, 128, 0, 0,
-57326,65533,65023,50159, 7647, 96, 3, 0,57324,65533,65023,50159, 7647,16480, 3, 0,
-57324,65533,65023,50175, 7631, 128, 3, 0,65516,64639,65535,12283,32895,65375, 0, 12,
-65534,65535,65535, 2047,32767, 0, 0, 0, 9622,65264,60590,15359, 8223,12288, 0, 0,
- 1, 0, 0, 0,65279,65535, 2047,65534, 3843,65279,65535, 8191, 0, 0, 0, 0,
-65535,65535,63227, 327, 0, 1023, 0, 0, 0, 0,65535,65535, 63,65535,65535, 127,
-65535,65535,65535,65535,65535,33791,65535,65535,65535,65535,65287,65535,65535,65535,65535, 1023,
-65407,65535,65535,65535,15743,15743,65535,65535,15743,65535,32767,32573,32573,65407,32767,65535,
-32767,32573,65535,65535,65407, 2047, 0, 0, 0, 0,65535,65535,65535,65535,65535, 31,
-65534,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,
-65535,65535,65535,65535,65535,65535,40959, 127,65534, 2047,65535,65535,65535,65535, 2047, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,65535,65535,65535,65535, 511, 0, 0, 0,
- 0, 0,65535,65535,65527,65535,65535, 255,65535,65535, 1023, 0, 0, 0, 0, 0,
-65535,65535,65535,65535,65535,65535,65535,65535,65535, 4095,65535,65535,65535,65535,65535, 1023,
-65535,16191,65535,65535,16191,43775,65535,16383,65535,65535,65535,24543, 8156, 4047, 8191, 8156,
- 0, 0, 0, 0, 0, 0, 0,32768, 0, 0, 0, 0, 0, 0, 0, 0,
-64644,15919,48464, 1019, 0, 0,65535,65535, 15, 0, 0, 0, 0, 0, 0, 0,
- 192, 0, 1022, 1792,65534,65535,65535,65535,65535, 31,65534,65535,65535,65535,65535, 2047,
-65504,65535, 8191,65534,65535,65535,65535,65535,32767, 0,65535, 255, 0, 0, 0, 0,
-65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535, 63, 0, 0, 0, 0,
-65535,65535,65535,65535,65535,65535,65535,65535,65535,65535, 63, 0, 0, 0, 0, 0,
-65535,65535,65535,65535,65535,65535,65535,65535, 8191, 0, 0, 0, 0, 0, 0, 0,
-65535,65535,65535,65535,65535,65535,65535,65535,65535,65535, 15, 0, 0, 0, 0, 0,
-65535,65535,16383, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 127,41208,65023,24447,65499,65535,65535,65535,65535,65535,65535, 3, 0,65528,65535,65535,
-65535,65535,65535,16383, 0,65535,65535,65535,65535,65532,65535,65535, 255, 0, 0, 4095,
- 0, 0, 0, 0, 0, 0, 0,65495,65535,65535,65535,65535,65535,65535,65535, 8191,
- 0, 0,65534, 2047,65534, 2047,65472,65534,65535,16383,65535,32767,64764, 7420, 0, 0};
-
-const UInt16 UnicodeDigitBits[] = {
- 256, 0, 0, 0, 0, 0, 272, 0, 0, 288, 304, 320, 336, 352, 368, 384,
- 400, 0, 0, 416, 0, 0, 0, 432, 448, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 464,
- 0, 0, 0, 1023, 0, 0, 0, 0, 0, 0, 0, 524, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 1023, 0, 0, 0, 0, 0, 0, 0, 0, 1023,
- 0, 0, 0, 0, 0, 0,65472, 0, 0, 0, 0, 0, 0, 0,65472, 0,
- 0, 0, 0, 0, 0, 0,65472, 0, 0, 0, 0, 0, 0, 0,65472, 0,
- 0, 0, 0, 0, 0, 0,65472, 0, 0, 0, 0, 0, 0, 0,65408, 0,
- 0, 0, 0, 0, 0, 0,65472, 0, 0, 0, 0, 0, 0, 0,65472, 0,
- 0, 0, 0, 0, 0, 0,65472, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 1023, 0, 0, 0, 0, 0, 0, 0, 1023, 0, 0,
- 0, 0, 1023, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 1023, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0,65024, 3, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1023, 0,
- 0, 1023, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 1023, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
-
-const UInt16 UnicodeSpaceBits[] = {
- 256, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 272, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 288, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 304, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-15872, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0,
- 4095, 0,33536, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
-
-const UInt16 UnicodeXDigitBits[] = {
- 256, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 272,
- 0, 0, 0, 1023, 126, 0, 126, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 1023, 126, 0, 126, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
-
-// Uncomment if necessary
-//const UInt16 UnicodeCntrlBits[] = {
-// 256, 0, 0, 0, 0, 0, 0, 272, 0, 0, 0, 0, 0, 0, 0, 0,
-// 0, 0, 0, 0, 0, 0, 0, 0, 288, 0, 0, 0, 0, 0, 0, 0,
-// 304, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-// 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-// 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-// 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-// 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-// 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-// 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-// 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-// 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-// 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-// 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-// 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-// 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-// 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 320, 336,
-//65535,65535, 0, 0, 0, 0, 0,32768,65535,65535, 0, 0, 0, 0, 0, 0,
-//32768, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-//30720, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-//61440, 0,31744, 0, 0, 0,64512, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-// 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,32768,
-// 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3584};
-//
-//const UInt16 UnicodeGraphBits[] = {
-// 256, 1, 272, 288, 304, 320, 336, 352, 0, 368, 384, 400, 416, 432, 448, 464,
-// 480, 496, 512, 528, 544, 1, 560, 576, 592, 0, 0, 0, 0, 0, 608, 624,
-// 640, 656, 0, 672, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-// 688, 704, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
-// 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 720, 1, 1,
-// 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
-// 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
-// 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
-// 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
-// 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 736,
-// 1, 1, 1, 1, 752, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1,
-// 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
-// 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
-// 1, 1, 1, 1, 1, 1, 1, 768, 0, 0, 0, 0, 0, 0, 0, 0,
-// 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-// 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 784, 800, 1, 816, 832, 848,
-// 0, 0,65534,65535,65535,65535,65535,32767, 0, 0,65534,65535,65535,65535,65535,65535,
-//65535,65535,65532, 15, 0,65535,65535,65535,65535,65535,16383,63999, 3, 0,16415, 0,
-// 0, 0, 0, 0, 32, 0, 0,17408,55232,65535,65531,65535,32767,64767,65535, 15,
-//65535,65535,65535,65535,65535,65535,65535,65535,61443,65535,65535,65535, 6559,65535,65535, 831,
-// 0, 0, 0,65534,65535,65151,65534,65535, 1791, 0, 0,16384, 9,65535, 2047, 31,
-// 4096,34816,65534, 2047,65534, 63,16383,65535,65535,65535,65535,65535,65535, 8191, 8702, 8191,
-//16383,65535, 8191,65535, 0, 0, 0, 0,65535,65535,65535, 1, 0, 0, 0, 0,
-//65518,65535,65535,58367, 8191,65281,65535, 1,40942,65529,65023,50117, 6559,45184,65487, 3,
-//34788,65529,65023,50029, 6535,24064,65472, 31,45038,65531,65023,58349, 7103, 1,65473, 0,
-//40942,65529,65023,58317, 6543,45248,65475, 0,51180,54845,50968,50111, 7623, 128,65408, 0,
-//57326,65533,65023,50159, 7647, 96,65475, 0,57324,65533,65023,50159, 7647,16480,65475, 0,
-//57324,65533,65023,50175, 7631, 128,65475, 0,65516,64639,65535,12283,32895,65375, 0, 28,
-//65534,65535,65535, 2047,65535, 4095, 0, 0, 9622,65264,60590,15359, 8223,13311, 0, 0,
-//65521, 7, 1023,15360,65279,65535, 2047,65534, 3875,65279,65535, 8191, 0, 0, 0, 0,
-//65535,65535,63227, 327,65535, 1023, 0, 0, 0, 0,65535,65535, 63,65535,65535, 2175,
-//65535,65535,65535,65535,65535,33791,65535,65535,65535,65535,65287,65535,65535,65535,65535, 1023,
-//65407,65535,65535,65535,15743,15743,65535,65535,15743,65535,32767,32573,32573,65407,32767,65535,
-//32767,32573,65535,65535,65407, 2047,65534, 3, 0, 0,65535,65535,65535,65535,65535, 31,
-//65534,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,
-//65535,65535,65535,65535,65535,65535,65535, 127,65534, 8191,65535,65535,65535,65535,16383, 0,
-// 0, 0, 0, 0, 0, 0, 0, 0,65535,65535,65535,65535, 511, 6128, 1023, 0,
-// 2047, 1023,65535,65535,65527,65535,65535, 255,65535,65535, 1023, 0, 0, 0, 0, 0,
-//65535,65535,65535,65535,65535,65535,65535,65535,65535, 4095,65535,65535,65535,65535,65535, 1023,
-//65535,16191,65535,65535,16191,43775,65535,16383,65535,65535,65535,24543, 8156, 4047, 8191, 8156,
-// 0,65535, 255,65535,16239, 0, 0,57344,24576, 0, 0, 0, 0, 0, 0, 0,
-//64644,15919,48464, 1019, 0, 0,65535,65535, 15, 0, 0, 0, 0, 0, 0, 0,
-// 0, 0, 1536, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-//65486,65523, 1022, 1793,65534,65535,65535,65535,65535, 31,65534,65535,65535,65535,65535, 4095,
-//65504,65535, 8191,65534,65535,65535,65535,65535,32767, 0,65535, 255, 0, 0, 0, 0,
-//65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535, 63, 0, 0, 0, 0,
-//65535,65535,65535,65535,65535,65535,65535,65535,65535,65535, 63, 0, 0, 0, 0, 0,
-//65535,65535,65535,65535,65535,65535,65535,65535, 8191, 0, 0, 0, 0, 0, 0, 0,
-//65535,65535,65535,65535,65535,65535,65535,65535,65535,65535, 15, 0, 0, 0, 0, 0,
-//65535,65535,16383, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-// 127,41208,65023,24447,65499,65535,65535,65535,65535,65535,65535, 3, 0,65528,65535,65535,
-//65535,65535,65535,65535, 0,65535,65535,65535,65535,65532,65535,65535, 255, 0, 0, 4095,
-// 0, 0, 0,65535,65055,65527, 3339,65495,65535,65535,65535,65535,65535,65535,65535, 8191,
-//63470,36863,65535,49151,65534,12287,65534,65534,65535,16383,65535,32767,64764, 7420, 0, 0};
-//
-//const UInt16 UnicodePrintBits[] = {
-// 256, 1, 272, 288, 304, 320, 336, 352, 0, 368, 384, 400, 416, 432, 448, 464,
-// 480, 496, 512, 528, 544, 1, 560, 576, 592, 0, 0, 0, 0, 0, 608, 624,
-// 640, 656, 0, 672, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-// 688, 704, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
-// 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 720, 1, 1,
-// 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
-// 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
-// 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
-// 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
-// 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 736,
-// 1, 1, 1, 1, 752, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1,
-// 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
-// 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
-// 1, 1, 1, 1, 1, 1, 1, 768, 0, 0, 0, 0, 0, 0, 0, 0,
-// 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-// 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 784, 800, 1, 816, 832, 848,
-// 512, 0,65535,65535,65535,65535,65535,32767, 0, 0,65535,65535,65535,65535,65535,65535,
-//65535,65535,65532, 15, 0,65535,65535,65535,65535,65535,16383,63999, 3, 0,16415, 0,
-// 0, 0, 0, 0, 32, 0, 0,17408,55232,65535,65531,65535,32767,64767,65535, 15,
-//65535,65535,65535,65535,65535,65535,65535,65535,61443,65535,65535,65535, 6559,65535,65535, 831,
-// 0, 0, 0,65534,65535,65151,65534,65535, 1791, 0, 0,16384, 9,65535, 2047, 31,
-// 4096,34816,65534, 2047,65534, 63,16383,65535,65535,65535,65535,65535,65535, 8191, 8702, 8191,
-//16383,65535, 8191,65535, 0, 0, 0, 0,65535,65535,65535, 1, 0, 0, 0, 0,
-//65518,65535,65535,58367, 8191,65281,65535, 1,40942,65529,65023,50117, 6559,45184,65487, 3,
-//34788,65529,65023,50029, 6535,24064,65472, 31,45038,65531,65023,58349, 7103, 1,65473, 0,
-//40942,65529,65023,58317, 6543,45248,65475, 0,51180,54845,50968,50111, 7623, 128,65408, 0,
-//57326,65533,65023,50159, 7647, 96,65475, 0,57324,65533,65023,50159, 7647,16480,65475, 0,
-//57324,65533,65023,50175, 7631, 128,65475, 0,65516,64639,65535,12283,32895,65375, 0, 28,
-//65534,65535,65535, 2047,65535, 4095, 0, 0, 9622,65264,60590,15359, 8223,13311, 0, 0,
-//65521, 7, 1023,15360,65279,65535, 2047,65534, 3875,65279,65535, 8191, 0, 0, 0, 0,
-//65535,65535,63227, 327,65535, 1023, 0, 0, 0, 0,65535,65535, 63,65535,65535, 2175,
-//65535,65535,65535,65535,65535,33791,65535,65535,65535,65535,65287,65535,65535,65535,65535, 1023,
-//65407,65535,65535,65535,15743,15743,65535,65535,15743,65535,32767,32573,32573,65407,32767,65535,
-//32767,32573,65535,65535,65407, 2047,65534, 3, 0, 0,65535,65535,65535,65535,65535, 31,
-//65534,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,
-//65535,65535,65535,65535,65535,65535,65535, 127,65534, 8191,65535,65535,65535,65535,16383, 0,
-// 0, 0, 0, 0, 0, 0, 0, 0,65535,65535,65535,65535, 511, 6128, 1023, 0,
-// 2047, 1023,65535,65535,65527,65535,65535, 255,65535,65535, 1023, 0, 0, 0, 0, 0,
-//65535,65535,65535,65535,65535,65535,65535,65535,65535, 4095,65535,65535,65535,65535,65535, 1023,
-//65535,16191,65535,65535,16191,43775,65535,16383,65535,65535,65535,24543, 8156, 4047, 8191, 8156,
-// 0,65535, 255,65535,16239, 0, 0,57344,24576, 0, 0, 0, 0, 0, 0, 0,
-//64644,15919,48464, 1019, 0, 0,65535,65535, 15, 0, 0, 0, 0, 0, 0, 0,
-// 0, 0, 1536, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-//65487,65523, 1022, 1793,65534,65535,65535,65535,65535, 31,65534,65535,65535,65535,65535, 4095,
-//65504,65535, 8191,65534,65535,65535,65535,65535,32767, 0,65535, 255, 0, 0, 0, 0,
-//65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535, 63, 0, 0, 0, 0,
-//65535,65535,65535,65535,65535,65535,65535,65535,65535,65535, 63, 0, 0, 0, 0, 0,
-//65535,65535,65535,65535,65535,65535,65535,65535, 8191, 0, 0, 0, 0, 0, 0, 0,
-//65535,65535,65535,65535,65535,65535,65535,65535,65535,65535, 15, 0, 0, 0, 0, 0,
-//65535,65535,16383, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-// 127,41208,65023,24447,65499,65535,65535,65535,65535,65535,65535, 3, 0,65528,65535,65535,
-//65535,65535,65535,65535, 0,65535,65535,65535,65535,65532,65535,65535, 255, 0, 0, 4095,
-// 0, 0, 0,65535,65055,65527, 3339,65495,65535,65535,65535,65535,65535,65535,65535,40959,
-//63470,36863,65535,49151,65534,12287,65534,65534,65535,16383,65535,32767,64764, 7420, 0, 0};
-//
-//const UInt16 UnicodePunctBits[] = {
-// 256, 0, 0, 272, 0, 288, 304, 320, 0, 336, 0, 0, 0, 352, 368, 384,
-// 400, 0, 0, 416, 0, 0, 432, 448, 464, 0, 0, 0, 0, 0, 0, 0,
-// 480, 0, 0, 496, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-// 512, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-// 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-// 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-// 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-// 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-// 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-// 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-// 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-// 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-// 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-// 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-// 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-// 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 528, 544, 560,
-// 0, 0,65534,64512, 1,63488, 1,30720, 0, 0,65534,65535, 0, 128, 0, 128,
-// 0, 0, 0, 0, 0, 0, 0,16384, 128, 0, 0, 0, 0, 0, 0, 0,
-// 0, 0, 0, 0, 0,64512, 0, 0, 1536, 0, 0,16384, 9, 0, 0, 24,
-// 4096,34816, 0, 0, 0, 0,15360, 0, 0, 0, 0, 0, 0, 16, 0, 0,
-//16383, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-// 0, 0, 0, 0, 0, 0, 48, 1, 0, 0, 0, 0, 0, 0, 0, 0,
-// 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16,
-// 0, 0, 0, 0,32768, 3072, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-//65520, 7, 0,15360, 0, 0, 0, 0, 32, 0, 0, 0, 0, 0, 0, 0,
-// 0, 0, 0, 0,64512, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2048,
-// 0, 0, 0, 0, 0, 0, 510, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-// 0, 0, 0, 0, 0, 0,24576, 0, 0, 6144, 0, 0, 0, 0,14336, 0,
-// 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6128, 0, 0,
-// 2047, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-// 0,65535, 255,65535,16239, 0, 0,24576,24576, 0, 0, 0, 0, 0, 0, 0,
-// 0, 0, 1536, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-//65294,65523, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2048,
-// 0, 0, 0,49152, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-// 0, 0, 0,65535,65055,65527, 3339, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-//63470,35840, 1,47104, 0,10240, 62, 0, 0, 0, 0, 0, 0, 0, 0, 0};
-//
-//const UInt16 UnicodeLowerBits[] = {
-// 256, 272, 288, 304, 320, 336, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-// 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 352, 368,
-// 384, 400, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-// 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-// 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-// 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-// 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-// 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-// 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-// 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-// 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-// 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-// 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-// 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-// 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-// 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 416, 0, 0, 0, 432,
-// 0, 0, 0, 0, 0, 0,65534, 2047, 0, 0, 0, 0, 0,32768,65535,65407,
-//43690,43690,43690,21930,43861,43690,43690,54442,12585,20004,11562,58961,23392,46421,43690,43565,
-//43690,43690,43688, 10, 0,65535,65535,65535,65535,65535,16383, 0, 0, 0, 0, 0,
-// 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,61440,65535,32767,43235,43690, 15,
-// 0, 0, 0,65535,65535,65535,43690,43690,40962,43690,43690,43690, 4372,43690,43690, 554,
-// 0, 0, 0, 0, 0, 0,65534,65535, 255, 0, 0, 0, 0, 0, 0, 0,
-//43690,43690,43690,43690,43690,43690,43690,43690,43690, 4074,43690,43690,43690,43690,43690, 682,
-// 255, 63, 255, 255, 63, 255, 255,16383,65535,65535,65535,20703, 4316, 207, 255, 4316,
-// 0, 0, 0, 0, 0, 0, 0,32768, 0, 0, 0, 0, 0, 0, 0, 0,
-//50176, 8,32768, 528, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-// 127, 248, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-// 0, 0, 0, 0,65534, 2047, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
-//
-//const UInt16 UnicodeUpperBits[] = {
-// 256, 272, 288, 304, 320, 336, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-// 352, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 368, 384,
-// 0, 400, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-// 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-// 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-// 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-// 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-// 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-// 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-// 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-// 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-// 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-// 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-// 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-// 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-// 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 416,
-// 0, 0, 0, 0,65534, 2047, 0, 0, 0, 0, 0, 0,65535,32639, 0, 0,
-//21845,21845,21845,43605,21674,21845,21845,11093,52950,45531,53973, 4526,44464,19114,21845,21974,
-//21845,21845,21844, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-// 0, 0, 0, 0, 0, 0, 0, 0,55104,65534, 4091, 0, 0,21532,21845, 0,
-//65535,65535,65535, 0, 0, 0,21845,21845,20481,21845,21845,21845, 2187,21845,21845, 277,
-// 0, 0, 0,65534,65535, 127, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-// 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,65535,65535, 63, 0, 0, 0,
-//21845,21845,21845,21845,21845,21845,21845,21845,21845, 21,21845,21845,21845,21845,21845, 341,
-//65280,16128,65280,65280,16128,43520,65280, 0,65280,65280,65280, 7936, 7936, 3840, 7936, 7936,
-//14468,15911,15696, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-// 0, 0,65534, 2047, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
-
-
-// MA: March 19, 2010
-// Modified ToUpper and ToLower tables to match values expected by AS3 tests.
-// ToLower modifications:
-// 304 -> 105
-// 1024 -> 1104 *
-// 1037 -> 1117 *
-// UoUpper modifications:
-// 255 -> 376
-// 305 -> 73
-// 383 -> 83
-// 1104 -> 1024 *
-// 1117 -> 1037 *
-// Entries marked with a '*' don't make complete sense based on Unicode manual, although
-// they match AS3.
-
-
-static const UInt16 UnicodeToUpperBits[] = {
- 256, 272, 288, 304, 320, 336, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 352, 368,
- 0, 384, 0, 0, 400, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 416,
- 0, 0, 0, 0, 0, 0,65534, 2047, 0, 0, 0, 0, 0, 0,65535,65407,
-43690,43690,43690,21674,43349,43690,43690,54442, 4392, 516, 8490, 8785,21056,46421,43690,43048, // MA: Modified for AS3.
-43690, 170, 0, 0, 0, 2776,33545, 36, 3336, 4, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,61440,65534,32767, 0,43688, 0,
- 0, 0, 0,65535,65535,65535,43690,43690, 2,43690,43690,43690, 4372,43690,35498, 554, // MA: Modified for AS3.
- 0, 0, 0, 0, 0, 0,65534,65535, 127, 0, 0, 0, 0, 0, 0, 0,
-43690,43690,43690,43690,43690,43690,43690,43690,43690, 42,43690,43690,43690,43690,43690, 682,
- 255, 63, 255, 255, 63, 170, 255,16383, 0, 0, 0, 3, 0, 3, 35, 0,
- 0, 0, 0, 0, 0, 0, 0,65535, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,65535, 1023, 0,
- 0, 0, 0, 0,65534, 2047, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
-
-static const UInt16 UnicodeToLowerBits[] = {
- 256, 272, 288, 304, 320, 336, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 352, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 368, 384,
- 0, 400, 0, 0, 416, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 432,
- 0, 0, 0, 0,65534, 2047, 0, 0, 0, 0, 0, 0,65535,32639, 0, 0,
-21845,21845,21845,43605,21674,21845,21845,11093,52950,45531,53909, 4526,42128,19114,21845,21522,// MA: Modidied for AS3.
-21845, 85, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,55104,65534, 4091, 0, 0, 0,21844, 0,
-65535,65535,65535, 0, 0, 0,21845,21845, 1,21845,21845,21845, 2186,21845,17749, 277,
- 0, 0, 0,65534,65535, 127, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,65535,65535, 63, 0, 0, 0,
-21845,21845,21845,21845,21845,21845,21845,21845,21845, 21,21845,21845,21845,21845,21845, 341,
-65280,16128,65280,65280,16128,43520,65280, 0, 0, 0, 0, 3840, 3840, 3840, 7936, 3840,
- 0, 0, 0, 0, 0, 0,65535, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,65472,65535, 0, 0, 0,
- 0, 0,65534, 2047, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
-
-struct GUnicodePairType
-{
- UInt16 Key, Value;
-};
-
-static inline bool CmpUnicodeKey(const GUnicodePairType& a, UInt16 key)
-{
- return a.Key < key;
-}
-
-static const GUnicodePairType UnicodeToUpperTable[] = {
-{ 97, 65}, { 98, 66}, { 99, 67}, { 100, 68}, { 101, 69}, { 102, 70}, { 103, 71},
-{ 104, 72}, { 105, 73}, { 106, 74}, { 107, 75}, { 108, 76}, { 109, 77}, { 110, 78},
-{ 111, 79}, { 112, 80}, { 113, 81}, { 114, 82}, { 115, 83}, { 116, 84}, { 117, 85},
-{ 118, 86}, { 119, 87}, { 120, 88}, { 121, 89}, { 122, 90}, { 224, 192}, { 225, 193},
-{ 226, 194}, { 227, 195}, { 228, 196}, { 229, 197}, { 230, 198}, { 231, 199}, { 232, 200},
-{ 233, 201}, { 234, 202}, { 235, 203}, { 236, 204}, { 237, 205}, { 238, 206}, { 239, 207},
-{ 240, 208}, { 241, 209}, { 242, 210}, { 243, 211}, { 244, 212}, { 245, 213}, { 246, 214},
-{ 248, 216}, { 249, 217}, { 250, 218}, { 251, 219}, { 252, 220}, { 253, 221}, { 254, 222},
-{ 255, 376}, { 257, 256}, { 259, 258}, { 261, 260}, { 263, 262}, { 265, 264}, { 267, 266},
-{ 269, 268}, { 271, 270}, { 273, 272}, { 275, 274}, { 277, 276}, { 279, 278}, { 281, 280},
-{ 283, 282}, { 285, 284}, { 287, 286}, { 289, 288}, { 291, 290}, { 293, 292}, { 295, 294},
-{ 297, 296}, { 299, 298}, { 301, 300}, { 303, 302}, { 305, 73}, { 307, 306}, { 309, 308}, { 311, 310},
-{ 314, 313}, { 316, 315}, { 318, 317}, { 320, 319}, { 322, 321}, { 324, 323}, { 326, 325},
-{ 328, 327}, { 331, 330}, { 333, 332}, { 335, 334}, { 337, 336}, { 339, 338}, { 341, 340},
-{ 343, 342}, { 345, 344}, { 347, 346}, { 349, 348}, { 351, 350}, { 353, 352}, { 355, 354},
-{ 357, 356}, { 359, 358}, { 361, 360}, { 363, 362}, { 365, 364}, { 367, 366}, { 369, 368},
-{ 371, 370}, { 373, 372}, { 375, 374}, { 378, 377}, { 380, 379}, { 382, 381}, { 383, 83}, { 387, 386},
-{ 389, 388}, { 392, 391}, { 396, 395}, { 402, 401}, { 409, 408}, { 417, 416}, { 419, 418},
-{ 421, 420}, { 424, 423}, { 429, 428}, { 432, 431}, { 436, 435}, { 438, 437}, { 441, 440},
-{ 445, 444}, { 454, 452}, { 457, 455}, { 460, 458}, { 462, 461}, { 464, 463}, { 466, 465},
-{ 468, 467}, { 470, 469}, { 472, 471}, { 474, 473}, { 476, 475}, { 477, 398}, { 479, 478},
-{ 481, 480}, { 483, 482}, { 485, 484}, { 487, 486}, { 489, 488}, { 491, 490}, { 493, 492},
-{ 495, 494}, { 499, 497}, { 501, 500}, { 507, 506}, { 509, 508}, { 511, 510}, { 513, 512},
-{ 515, 514}, { 517, 516}, { 519, 518}, { 521, 520}, { 523, 522}, { 525, 524}, { 527, 526},
-{ 529, 528}, { 531, 530}, { 533, 532}, { 535, 534}, { 595, 385}, { 596, 390}, { 598, 393},
-{ 599, 394}, { 601, 399}, { 603, 400}, { 608, 403}, { 611, 404}, { 616, 407}, { 617, 406},
-{ 623, 412}, { 626, 413}, { 629, 415}, { 643, 425}, { 648, 430}, { 650, 433}, { 651, 434},
-{ 658, 439}, { 940, 902}, { 941, 904}, { 942, 905}, { 943, 906}, { 945, 913}, { 946, 914},
-{ 947, 915}, { 948, 916}, { 949, 917}, { 950, 918}, { 951, 919}, { 952, 920}, { 953, 921},
-{ 954, 922}, { 955, 923}, { 956, 924}, { 957, 925}, { 958, 926}, { 959, 927}, { 960, 928},
-{ 961, 929}, { 962, 931}, { 963, 931}, { 964, 932}, { 965, 933}, { 966, 934}, { 967, 935},
-{ 968, 936}, { 969, 937}, { 970, 938}, { 971, 939}, { 972, 908}, { 973, 910}, { 974, 911},
-{ 995, 994}, { 997, 996}, { 999, 998}, { 1001, 1000}, { 1003, 1002}, { 1005, 1004}, { 1007, 1006},
-{ 1072, 1040}, { 1073, 1041}, { 1074, 1042}, { 1075, 1043}, { 1076, 1044}, { 1077, 1045}, { 1078, 1046},
-{ 1079, 1047}, { 1080, 1048}, { 1081, 1049}, { 1082, 1050}, { 1083, 1051}, { 1084, 1052}, { 1085, 1053},
-{ 1086, 1054}, { 1087, 1055}, { 1088, 1056}, { 1089, 1057}, { 1090, 1058}, { 1091, 1059}, { 1092, 1060},
-{ 1093, 1061}, { 1094, 1062}, { 1095, 1063}, { 1096, 1064}, { 1097, 1065}, { 1098, 1066}, { 1099, 1067},
-{ 1100, 1068}, { 1101, 1069}, { 1102, 1070}, { 1103, 1071}, { 1104, 1024}, { 1105, 1025}, { 1106, 1026}, { 1107, 1027},
-{ 1108, 1028}, { 1109, 1029}, { 1110, 1030}, { 1111, 1031}, { 1112, 1032}, { 1113, 1033}, { 1114, 1034},
-{ 1115, 1035}, { 1116, 1036}, { 1117, 1037}, { 1118, 1038}, { 1119, 1039}, { 1121, 1120}, { 1123, 1122}, { 1125, 1124},
-{ 1127, 1126}, { 1129, 1128}, { 1131, 1130}, { 1133, 1132}, { 1135, 1134}, { 1137, 1136}, { 1139, 1138},
-{ 1141, 1140}, { 1143, 1142}, { 1145, 1144}, { 1147, 1146}, { 1149, 1148}, { 1151, 1150}, { 1153, 1152},
-{ 1169, 1168}, { 1171, 1170}, { 1173, 1172}, { 1175, 1174}, { 1177, 1176}, { 1179, 1178}, { 1181, 1180},
-{ 1183, 1182}, { 1185, 1184}, { 1187, 1186}, { 1189, 1188}, { 1191, 1190}, { 1193, 1192}, { 1195, 1194},
-{ 1197, 1196}, { 1199, 1198}, { 1201, 1200}, { 1203, 1202}, { 1205, 1204}, { 1207, 1206}, { 1209, 1208},
-{ 1211, 1210}, { 1213, 1212}, { 1215, 1214}, { 1218, 1217}, { 1220, 1219}, { 1224, 1223}, { 1228, 1227},
-{ 1233, 1232}, { 1235, 1234}, { 1237, 1236}, { 1239, 1238}, { 1241, 1240}, { 1243, 1242}, { 1245, 1244},
-{ 1247, 1246}, { 1249, 1248}, { 1251, 1250}, { 1253, 1252}, { 1255, 1254}, { 1257, 1256}, { 1259, 1258},
-{ 1263, 1262}, { 1265, 1264}, { 1267, 1266}, { 1269, 1268}, { 1273, 1272}, { 1377, 1329}, { 1378, 1330},
-{ 1379, 1331}, { 1380, 1332}, { 1381, 1333}, { 1382, 1334}, { 1383, 1335}, { 1384, 1336}, { 1385, 1337},
-{ 1386, 1338}, { 1387, 1339}, { 1388, 1340}, { 1389, 1341}, { 1390, 1342}, { 1391, 1343}, { 1392, 1344},
-{ 1393, 1345}, { 1394, 1346}, { 1395, 1347}, { 1396, 1348}, { 1397, 1349}, { 1398, 1350}, { 1399, 1351},
-{ 1400, 1352}, { 1401, 1353}, { 1402, 1354}, { 1403, 1355}, { 1404, 1356}, { 1405, 1357}, { 1406, 1358},
-{ 1407, 1359}, { 1408, 1360}, { 1409, 1361}, { 1410, 1362}, { 1411, 1363}, { 1412, 1364}, { 1413, 1365},
-{ 1414, 1366}, { 7681, 7680}, { 7683, 7682}, { 7685, 7684}, { 7687, 7686}, { 7689, 7688}, { 7691, 7690},
-{ 7693, 7692}, { 7695, 7694}, { 7697, 7696}, { 7699, 7698}, { 7701, 7700}, { 7703, 7702}, { 7705, 7704},
-{ 7707, 7706}, { 7709, 7708}, { 7711, 7710}, { 7713, 7712}, { 7715, 7714}, { 7717, 7716}, { 7719, 7718},
-{ 7721, 7720}, { 7723, 7722}, { 7725, 7724}, { 7727, 7726}, { 7729, 7728}, { 7731, 7730}, { 7733, 7732},
-{ 7735, 7734}, { 7737, 7736}, { 7739, 7738}, { 7741, 7740}, { 7743, 7742}, { 7745, 7744}, { 7747, 7746},
-{ 7749, 7748}, { 7751, 7750}, { 7753, 7752}, { 7755, 7754}, { 7757, 7756}, { 7759, 7758}, { 7761, 7760},
-{ 7763, 7762}, { 7765, 7764}, { 7767, 7766}, { 7769, 7768}, { 7771, 7770}, { 7773, 7772}, { 7775, 7774},
-{ 7777, 7776}, { 7779, 7778}, { 7781, 7780}, { 7783, 7782}, { 7785, 7784}, { 7787, 7786}, { 7789, 7788},
-{ 7791, 7790}, { 7793, 7792}, { 7795, 7794}, { 7797, 7796}, { 7799, 7798}, { 7801, 7800}, { 7803, 7802},
-{ 7805, 7804}, { 7807, 7806}, { 7809, 7808}, { 7811, 7810}, { 7813, 7812}, { 7815, 7814}, { 7817, 7816},
-{ 7819, 7818}, { 7821, 7820}, { 7823, 7822}, { 7825, 7824}, { 7827, 7826}, { 7829, 7828}, { 7841, 7840},
-{ 7843, 7842}, { 7845, 7844}, { 7847, 7846}, { 7849, 7848}, { 7851, 7850}, { 7853, 7852}, { 7855, 7854},
-{ 7857, 7856}, { 7859, 7858}, { 7861, 7860}, { 7863, 7862}, { 7865, 7864}, { 7867, 7866}, { 7869, 7868},
-{ 7871, 7870}, { 7873, 7872}, { 7875, 7874}, { 7877, 7876}, { 7879, 7878}, { 7881, 7880}, { 7883, 7882},
-{ 7885, 7884}, { 7887, 7886}, { 7889, 7888}, { 7891, 7890}, { 7893, 7892}, { 7895, 7894}, { 7897, 7896},
-{ 7899, 7898}, { 7901, 7900}, { 7903, 7902}, { 7905, 7904}, { 7907, 7906}, { 7909, 7908}, { 7911, 7910},
-{ 7913, 7912}, { 7915, 7914}, { 7917, 7916}, { 7919, 7918}, { 7921, 7920}, { 7923, 7922}, { 7925, 7924},
-{ 7927, 7926}, { 7929, 7928}, { 7936, 7944}, { 7937, 7945}, { 7938, 7946}, { 7939, 7947}, { 7940, 7948},
-{ 7941, 7949}, { 7942, 7950}, { 7943, 7951}, { 7952, 7960}, { 7953, 7961}, { 7954, 7962}, { 7955, 7963},
-{ 7956, 7964}, { 7957, 7965}, { 7968, 7976}, { 7969, 7977}, { 7970, 7978}, { 7971, 7979}, { 7972, 7980},
-{ 7973, 7981}, { 7974, 7982}, { 7975, 7983}, { 7984, 7992}, { 7985, 7993}, { 7986, 7994}, { 7987, 7995},
-{ 7988, 7996}, { 7989, 7997}, { 7990, 7998}, { 7991, 7999}, { 8000, 8008}, { 8001, 8009}, { 8002, 8010},
-{ 8003, 8011}, { 8004, 8012}, { 8005, 8013}, { 8017, 8025}, { 8019, 8027}, { 8021, 8029}, { 8023, 8031},
-{ 8032, 8040}, { 8033, 8041}, { 8034, 8042}, { 8035, 8043}, { 8036, 8044}, { 8037, 8045}, { 8038, 8046},
-{ 8039, 8047}, { 8048, 8122}, { 8049, 8123}, { 8050, 8136}, { 8051, 8137}, { 8052, 8138}, { 8053, 8139},
-{ 8054, 8154}, { 8055, 8155}, { 8056, 8184}, { 8057, 8185}, { 8058, 8170}, { 8059, 8171}, { 8060, 8186},
-{ 8061, 8187}, { 8112, 8120}, { 8113, 8121}, { 8144, 8152}, { 8145, 8153}, { 8160, 8168}, { 8161, 8169},
-{ 8165, 8172}, { 8560, 8544}, { 8561, 8545}, { 8562, 8546}, { 8563, 8547}, { 8564, 8548}, { 8565, 8549},
-{ 8566, 8550}, { 8567, 8551}, { 8568, 8552}, { 8569, 8553}, { 8570, 8554}, { 8571, 8555}, { 8572, 8556},
-{ 8573, 8557}, { 8574, 8558}, { 8575, 8559}, { 9424, 9398}, { 9425, 9399}, { 9426, 9400}, { 9427, 9401},
-{ 9428, 9402}, { 9429, 9403}, { 9430, 9404}, { 9431, 9405}, { 9432, 9406}, { 9433, 9407}, { 9434, 9408},
-{ 9435, 9409}, { 9436, 9410}, { 9437, 9411}, { 9438, 9412}, { 9439, 9413}, { 9440, 9414}, { 9441, 9415},
-{ 9442, 9416}, { 9443, 9417}, { 9444, 9418}, { 9445, 9419}, { 9446, 9420}, { 9447, 9421}, { 9448, 9422},
-{ 9449, 9423}, {65345,65313}, {65346,65314}, {65347,65315}, {65348,65316}, {65349,65317}, {65350,65318},
-{65351,65319}, {65352,65320}, {65353,65321}, {65354,65322}, {65355,65323}, {65356,65324}, {65357,65325},
-{65358,65326}, {65359,65327}, {65360,65328}, {65361,65329}, {65362,65330}, {65363,65331}, {65364,65332},
-{65365,65333}, {65366,65334}, {65367,65335}, {65368,65336}, {65369,65337}, {65370,65338}, {65535, 0}};
-
-static const GUnicodePairType UnicodeToLowerTable[] = {
-{ 65, 97}, { 66, 98}, { 67, 99}, { 68, 100}, { 69, 101}, { 70, 102}, { 71, 103},
-{ 72, 104}, { 73, 105}, { 74, 106}, { 75, 107}, { 76, 108}, { 77, 109}, { 78, 110},
-{ 79, 111}, { 80, 112}, { 81, 113}, { 82, 114}, { 83, 115}, { 84, 116}, { 85, 117},
-{ 86, 118}, { 87, 119}, { 88, 120}, { 89, 121}, { 90, 122}, { 192, 224}, { 193, 225},
-{ 194, 226}, { 195, 227}, { 196, 228}, { 197, 229}, { 198, 230}, { 199, 231}, { 200, 232},
-{ 201, 233}, { 202, 234}, { 203, 235}, { 204, 236}, { 205, 237}, { 206, 238}, { 207, 239},
-{ 208, 240}, { 209, 241}, { 210, 242}, { 211, 243}, { 212, 244}, { 213, 245}, { 214, 246},
-{ 216, 248}, { 217, 249}, { 218, 250}, { 219, 251}, { 220, 252}, { 221, 253}, { 222, 254},
-{ 256, 257}, { 258, 259}, { 260, 261}, { 262, 263}, { 264, 265}, { 266, 267}, { 268, 269},
-{ 270, 271}, { 272, 273}, { 274, 275}, { 276, 277}, { 278, 279}, { 280, 281}, { 282, 283},
-{ 284, 285}, { 286, 287}, { 288, 289}, { 290, 291}, { 292, 293}, { 294, 295}, { 296, 297},
-{ 298, 299}, { 300, 301}, { 302, 303}, { 304, 105}, { 306, 307}, { 308, 309}, { 310, 311}, { 313, 314},
-{ 315, 316}, { 317, 318}, { 319, 320}, { 321, 322}, { 323, 324}, { 325, 326}, { 327, 328},
-{ 330, 331}, { 332, 333}, { 334, 335}, { 336, 337}, { 338, 339}, { 340, 341}, { 342, 343},
-{ 344, 345}, { 346, 347}, { 348, 349}, { 350, 351}, { 352, 353}, { 354, 355}, { 356, 357},
-{ 358, 359}, { 360, 361}, { 362, 363}, { 364, 365}, { 366, 367}, { 368, 369}, { 370, 371},
-{ 372, 373}, { 374, 375}, { 376, 255}, { 377, 378}, { 379, 380}, { 381, 382}, { 385, 595},
-{ 386, 387}, { 388, 389}, { 390, 596}, { 391, 392}, { 393, 598}, { 394, 599}, { 395, 396},
-{ 398, 477}, { 399, 601}, { 400, 603}, { 401, 402}, { 403, 608}, { 404, 611}, { 406, 617},
-{ 407, 616}, { 408, 409}, { 412, 623}, { 413, 626}, { 415, 629}, { 416, 417}, { 418, 419},
-{ 420, 421}, { 423, 424}, { 425, 643}, { 428, 429}, { 430, 648}, { 431, 432}, { 433, 650},
-{ 434, 651}, { 435, 436}, { 437, 438}, { 439, 658}, { 440, 441}, { 444, 445}, { 452, 454},
-{ 455, 457}, { 458, 460}, { 461, 462}, { 463, 464}, { 465, 466}, { 467, 468}, { 469, 470},
-{ 471, 472}, { 473, 474}, { 475, 476}, { 478, 479}, { 480, 481}, { 482, 483}, { 484, 485},
-{ 486, 487}, { 488, 489}, { 490, 491}, { 492, 493}, { 494, 495}, { 497, 499}, { 500, 501},
-{ 506, 507}, { 508, 509}, { 510, 511}, { 512, 513}, { 514, 515}, { 516, 517}, { 518, 519},
-{ 520, 521}, { 522, 523}, { 524, 525}, { 526, 527}, { 528, 529}, { 530, 531}, { 532, 533},
-{ 534, 535}, { 902, 940}, { 904, 941}, { 905, 942}, { 906, 943}, { 908, 972}, { 910, 973},
-{ 911, 974}, { 913, 945}, { 914, 946}, { 915, 947}, { 916, 948}, { 917, 949}, { 918, 950},
-{ 919, 951}, { 920, 952}, { 921, 953}, { 922, 954}, { 923, 955}, { 924, 956}, { 925, 957},
-{ 926, 958}, { 927, 959}, { 928, 960}, { 929, 961}, { 931, 963}, { 932, 964}, { 933, 965},
-{ 934, 966}, { 935, 967}, { 936, 968}, { 937, 969}, { 938, 970}, { 939, 971}, { 994, 995},
-{ 996, 997}, { 998, 999}, { 1000, 1001}, { 1002, 1003}, { 1004, 1005}, { 1006, 1007}, { 1024, 1104}, { 1025, 1105},
-{ 1026, 1106}, { 1027, 1107}, { 1028, 1108}, { 1029, 1109}, { 1030, 1110}, { 1031, 1111}, { 1032, 1112},
-{ 1033, 1113}, { 1034, 1114}, { 1035, 1115}, { 1036, 1116}, { 1037, 1117}, { 1038, 1118}, { 1039, 1119}, { 1040, 1072},
-{ 1041, 1073}, { 1042, 1074}, { 1043, 1075}, { 1044, 1076}, { 1045, 1077}, { 1046, 1078}, { 1047, 1079},
-{ 1048, 1080}, { 1049, 1081}, { 1050, 1082}, { 1051, 1083}, { 1052, 1084}, { 1053, 1085}, { 1054, 1086},
-{ 1055, 1087}, { 1056, 1088}, { 1057, 1089}, { 1058, 1090}, { 1059, 1091}, { 1060, 1092}, { 1061, 1093},
-{ 1062, 1094}, { 1063, 1095}, { 1064, 1096}, { 1065, 1097}, { 1066, 1098}, { 1067, 1099}, { 1068, 1100},
-{ 1069, 1101}, { 1070, 1102}, { 1071, 1103}, { 1120, 1121}, { 1122, 1123}, { 1124, 1125}, { 1126, 1127},
-{ 1128, 1129}, { 1130, 1131}, { 1132, 1133}, { 1134, 1135}, { 1136, 1137}, { 1138, 1139}, { 1140, 1141},
-{ 1142, 1143}, { 1144, 1145}, { 1146, 1147}, { 1148, 1149}, { 1150, 1151}, { 1152, 1153}, { 1168, 1169},
-{ 1170, 1171}, { 1172, 1173}, { 1174, 1175}, { 1176, 1177}, { 1178, 1179}, { 1180, 1181}, { 1182, 1183},
-{ 1184, 1185}, { 1186, 1187}, { 1188, 1189}, { 1190, 1191}, { 1192, 1193}, { 1194, 1195}, { 1196, 1197},
-{ 1198, 1199}, { 1200, 1201}, { 1202, 1203}, { 1204, 1205}, { 1206, 1207}, { 1208, 1209}, { 1210, 1211},
-{ 1212, 1213}, { 1214, 1215}, { 1217, 1218}, { 1219, 1220}, { 1223, 1224}, { 1227, 1228}, { 1232, 1233},
-{ 1234, 1235}, { 1236, 1237}, { 1238, 1239}, { 1240, 1241}, { 1242, 1243}, { 1244, 1245}, { 1246, 1247},
-{ 1248, 1249}, { 1250, 1251}, { 1252, 1253}, { 1254, 1255}, { 1256, 1257}, { 1258, 1259}, { 1262, 1263},
-{ 1264, 1265}, { 1266, 1267}, { 1268, 1269}, { 1272, 1273}, { 1329, 1377}, { 1330, 1378}, { 1331, 1379},
-{ 1332, 1380}, { 1333, 1381}, { 1334, 1382}, { 1335, 1383}, { 1336, 1384}, { 1337, 1385}, { 1338, 1386},
-{ 1339, 1387}, { 1340, 1388}, { 1341, 1389}, { 1342, 1390}, { 1343, 1391}, { 1344, 1392}, { 1345, 1393},
-{ 1346, 1394}, { 1347, 1395}, { 1348, 1396}, { 1349, 1397}, { 1350, 1398}, { 1351, 1399}, { 1352, 1400},
-{ 1353, 1401}, { 1354, 1402}, { 1355, 1403}, { 1356, 1404}, { 1357, 1405}, { 1358, 1406}, { 1359, 1407},
-{ 1360, 1408}, { 1361, 1409}, { 1362, 1410}, { 1363, 1411}, { 1364, 1412}, { 1365, 1413}, { 1366, 1414},
-{ 4256, 4304}, { 4257, 4305}, { 4258, 4306}, { 4259, 4307}, { 4260, 4308}, { 4261, 4309}, { 4262, 4310},
-{ 4263, 4311}, { 4264, 4312}, { 4265, 4313}, { 4266, 4314}, { 4267, 4315}, { 4268, 4316}, { 4269, 4317},
-{ 4270, 4318}, { 4271, 4319}, { 4272, 4320}, { 4273, 4321}, { 4274, 4322}, { 4275, 4323}, { 4276, 4324},
-{ 4277, 4325}, { 4278, 4326}, { 4279, 4327}, { 4280, 4328}, { 4281, 4329}, { 4282, 4330}, { 4283, 4331},
-{ 4284, 4332}, { 4285, 4333}, { 4286, 4334}, { 4287, 4335}, { 4288, 4336}, { 4289, 4337}, { 4290, 4338},
-{ 4291, 4339}, { 4292, 4340}, { 4293, 4341}, { 7680, 7681}, { 7682, 7683}, { 7684, 7685}, { 7686, 7687},
-{ 7688, 7689}, { 7690, 7691}, { 7692, 7693}, { 7694, 7695}, { 7696, 7697}, { 7698, 7699}, { 7700, 7701},
-{ 7702, 7703}, { 7704, 7705}, { 7706, 7707}, { 7708, 7709}, { 7710, 7711}, { 7712, 7713}, { 7714, 7715},
-{ 7716, 7717}, { 7718, 7719}, { 7720, 7721}, { 7722, 7723}, { 7724, 7725}, { 7726, 7727}, { 7728, 7729},
-{ 7730, 7731}, { 7732, 7733}, { 7734, 7735}, { 7736, 7737}, { 7738, 7739}, { 7740, 7741}, { 7742, 7743},
-{ 7744, 7745}, { 7746, 7747}, { 7748, 7749}, { 7750, 7751}, { 7752, 7753}, { 7754, 7755}, { 7756, 7757},
-{ 7758, 7759}, { 7760, 7761}, { 7762, 7763}, { 7764, 7765}, { 7766, 7767}, { 7768, 7769}, { 7770, 7771},
-{ 7772, 7773}, { 7774, 7775}, { 7776, 7777}, { 7778, 7779}, { 7780, 7781}, { 7782, 7783}, { 7784, 7785},
-{ 7786, 7787}, { 7788, 7789}, { 7790, 7791}, { 7792, 7793}, { 7794, 7795}, { 7796, 7797}, { 7798, 7799},
-{ 7800, 7801}, { 7802, 7803}, { 7804, 7805}, { 7806, 7807}, { 7808, 7809}, { 7810, 7811}, { 7812, 7813},
-{ 7814, 7815}, { 7816, 7817}, { 7818, 7819}, { 7820, 7821}, { 7822, 7823}, { 7824, 7825}, { 7826, 7827},
-{ 7828, 7829}, { 7840, 7841}, { 7842, 7843}, { 7844, 7845}, { 7846, 7847}, { 7848, 7849}, { 7850, 7851},
-{ 7852, 7853}, { 7854, 7855}, { 7856, 7857}, { 7858, 7859}, { 7860, 7861}, { 7862, 7863}, { 7864, 7865},
-{ 7866, 7867}, { 7868, 7869}, { 7870, 7871}, { 7872, 7873}, { 7874, 7875}, { 7876, 7877}, { 7878, 7879},
-{ 7880, 7881}, { 7882, 7883}, { 7884, 7885}, { 7886, 7887}, { 7888, 7889}, { 7890, 7891}, { 7892, 7893},
-{ 7894, 7895}, { 7896, 7897}, { 7898, 7899}, { 7900, 7901}, { 7902, 7903}, { 7904, 7905}, { 7906, 7907},
-{ 7908, 7909}, { 7910, 7911}, { 7912, 7913}, { 7914, 7915}, { 7916, 7917}, { 7918, 7919}, { 7920, 7921},
-{ 7922, 7923}, { 7924, 7925}, { 7926, 7927}, { 7928, 7929}, { 7944, 7936}, { 7945, 7937}, { 7946, 7938},
-{ 7947, 7939}, { 7948, 7940}, { 7949, 7941}, { 7950, 7942}, { 7951, 7943}, { 7960, 7952}, { 7961, 7953},
-{ 7962, 7954}, { 7963, 7955}, { 7964, 7956}, { 7965, 7957}, { 7976, 7968}, { 7977, 7969}, { 7978, 7970},
-{ 7979, 7971}, { 7980, 7972}, { 7981, 7973}, { 7982, 7974}, { 7983, 7975}, { 7992, 7984}, { 7993, 7985},
-{ 7994, 7986}, { 7995, 7987}, { 7996, 7988}, { 7997, 7989}, { 7998, 7990}, { 7999, 7991}, { 8008, 8000},
-{ 8009, 8001}, { 8010, 8002}, { 8011, 8003}, { 8012, 8004}, { 8013, 8005}, { 8025, 8017}, { 8027, 8019},
-{ 8029, 8021}, { 8031, 8023}, { 8040, 8032}, { 8041, 8033}, { 8042, 8034}, { 8043, 8035}, { 8044, 8036},
-{ 8045, 8037}, { 8046, 8038}, { 8047, 8039}, { 8120, 8112}, { 8121, 8113}, { 8122, 8048}, { 8123, 8049},
-{ 8136, 8050}, { 8137, 8051}, { 8138, 8052}, { 8139, 8053}, { 8152, 8144}, { 8153, 8145}, { 8154, 8054},
-{ 8155, 8055}, { 8168, 8160}, { 8169, 8161}, { 8170, 8058}, { 8171, 8059}, { 8172, 8165}, { 8184, 8056},
-{ 8185, 8057}, { 8186, 8060}, { 8187, 8061}, { 8544, 8560}, { 8545, 8561}, { 8546, 8562}, { 8547, 8563},
-{ 8548, 8564}, { 8549, 8565}, { 8550, 8566}, { 8551, 8567}, { 8552, 8568}, { 8553, 8569}, { 8554, 8570},
-{ 8555, 8571}, { 8556, 8572}, { 8557, 8573}, { 8558, 8574}, { 8559, 8575}, { 9398, 9424}, { 9399, 9425},
-{ 9400, 9426}, { 9401, 9427}, { 9402, 9428}, { 9403, 9429}, { 9404, 9430}, { 9405, 9431}, { 9406, 9432},
-{ 9407, 9433}, { 9408, 9434}, { 9409, 9435}, { 9410, 9436}, { 9411, 9437}, { 9412, 9438}, { 9413, 9439},
-{ 9414, 9440}, { 9415, 9441}, { 9416, 9442}, { 9417, 9443}, { 9418, 9444}, { 9419, 9445}, { 9420, 9446},
-{ 9421, 9447}, { 9422, 9448}, { 9423, 9449}, {65313,65345}, {65314,65346}, {65315,65347}, {65316,65348},
-{65317,65349}, {65318,65350}, {65319,65351}, {65320,65352}, {65321,65353}, {65322,65354}, {65323,65355},
-{65324,65356}, {65325,65357}, {65326,65358}, {65327,65359}, {65328,65360}, {65329,65361}, {65330,65362},
-{65331,65363}, {65332,65364}, {65333,65365}, {65334,65366}, {65335,65367}, {65336,65368}, {65337,65369},
-{65338,65370}, {65535, 0}};
-
-int OVR_CDECL OVR_towupper(wchar_t charCode)
-{
- // Don't use UnicodeUpperBits! It differs from UnicodeToUpperBits.
- if (UnicodeCharIs(UnicodeToUpperBits, charCode))
- {
- // To protect from memory overrun in case the character is not found
- // we use one extra fake element in the table {65536, 0}.
- UPInt idx = Alg::LowerBoundSliced(
- UnicodeToUpperTable,
- 0,
- sizeof(UnicodeToUpperTable) / sizeof(UnicodeToUpperTable[0]) - 1,
- (UInt16)charCode,
- CmpUnicodeKey);
- return UnicodeToUpperTable[idx].Value;
- }
- return charCode;
-}
-
-int OVR_CDECL OVR_towlower(wchar_t charCode)
-{
- // Don't use UnicodeLowerBits! It differs from UnicodeToLowerBits.
- if (UnicodeCharIs(UnicodeToLowerBits, charCode))
- {
- // To protect from memory overrun in case the character is not found
- // we use one extra fake element in the table {65536, 0}.
- UPInt idx = Alg::LowerBoundSliced(
- UnicodeToLowerTable,
- 0,
- sizeof(UnicodeToLowerTable) / sizeof(UnicodeToLowerTable[0]) - 1,
- (UInt16)charCode,
- CmpUnicodeKey);
- return UnicodeToLowerTable[idx].Value;
- }
- return charCode;
-}
-
-#endif //OVR_NO_WCTYPE
-
-} // OVR
+/************************************************************************************
+
+Filename : OVR_Std.cpp
+Content : Standard C function implementation
+Created : September 19, 2012
+Notes :
+
+Copyright : Copyright 2012 Oculus VR, Inc. All Rights reserved.
+
+Use of this software is subject to the terms of the Oculus license
+agreement provided at the time of installation or download, or which
+otherwise accompanies this software in either electronic or hard copy form.
+
+************************************************************************************/
+
+#include "OVR_Std.h"
+#include "OVR_Alg.h"
+
+// localeconv() call in OVR_strtod()
+#include <locale.h>
+
+namespace OVR {
+
+// Source for functions not available on all platforms is included here.
+
+// Case insensitive compare implemented in platform-specific way.
+int OVR_CDECL OVR_stricmp(const char* a, const char* b)
+{
+#if defined(OVR_OS_WIN32)
+ #if defined(OVR_CC_MSVC) && (OVR_CC_MSVC >= 1400)
+ return ::_stricmp(a, b);
+ #else
+ return ::stricmp(a, b);
+ #endif
+
+#else
+ return strcasecmp(a, b);
+#endif
+}
+
+int OVR_CDECL OVR_strnicmp(const char* a, const char* b, UPInt count)
+{
+#if defined(OVR_OS_WIN32)
+#if defined(OVR_CC_MSVC) && (OVR_CC_MSVC >= 1400)
+ return ::_strnicmp(a, b, count);
+#else
+ return ::strnicmp(a, b, count);
+#endif
+
+#else
+ return strncasecmp(a, b, count);
+#endif
+}
+
+wchar_t* OVR_CDECL OVR_wcscpy(wchar_t* dest, UPInt destsize, const wchar_t* src)
+{
+#if defined(OVR_MSVC_SAFESTRING)
+ wcscpy_s(dest, destsize, src);
+ return dest;
+#elif defined(OVR_OS_WIN32)
+ OVR_UNUSED(destsize);
+ wcscpy(dest, src);
+ return dest;
+#else
+ UPInt l = OVR_wcslen(src) + 1; // incl term null
+ l = (l < destsize) ? l : destsize;
+ memcpy(dest, src, l * sizeof(wchar_t));
+ return dest;
+#endif
+}
+
+wchar_t* OVR_CDECL OVR_wcsncpy(wchar_t* dest, UPInt destsize, const wchar_t* src, UPInt count)
+{
+#if defined(OVR_MSVC_SAFESTRING)
+ wcsncpy_s(dest, destsize, src, count);
+ return dest;
+#else
+ UPInt srclen = OVR_wcslen(src);
+ UPInt l = Alg::Min(srclen, count);
+ l = (l < destsize) ? l : destsize;
+ memcpy(dest, src, l * sizeof(wchar_t));
+ if (count > srclen)
+ {
+ UPInt remLen = Alg::Min(destsize - l, (count - srclen));
+ memset(&dest[l], 0, sizeof(wchar_t)*remLen);
+ }
+ else if (l < destsize)
+ dest[l] = 0;
+ return dest;
+#endif
+}
+
+
+wchar_t* OVR_CDECL OVR_wcscat(wchar_t* dest, UPInt destsize, const wchar_t* src)
+{
+#if defined(OVR_MSVC_SAFESTRING)
+ wcscat_s(dest, destsize, src);
+ return dest;
+#elif defined(OVR_OS_WIN32)
+ OVR_UNUSED(destsize);
+ wcscat(dest, src);
+ return dest;
+#else
+ UPInt dstlen = OVR_wcslen(dest); // do not incl term null
+ UPInt srclen = OVR_wcslen(src) + 1; // incl term null
+ UPInt copylen = (dstlen + srclen < destsize) ? srclen : destsize - dstlen;
+ memcpy(dest + dstlen, src, copylen * sizeof(wchar_t));
+ return dest;
+#endif
+}
+
+UPInt OVR_CDECL OVR_wcslen(const wchar_t* str)
+{
+#if defined(OVR_OS_WIN32)
+ return wcslen(str);
+#else
+ UPInt i = 0;
+ while(str[i] != '\0')
+ ++i;
+ return i;
+#endif
+}
+
+int OVR_CDECL OVR_wcscmp(const wchar_t* a, const wchar_t* b)
+{
+#if defined(OVR_OS_WIN32) || defined(OVR_OS_LINUX)
+ return wcscmp(a, b);
+#else
+ // not supported, use custom implementation
+ const wchar_t *pa = a, *pb = b;
+ while (*pa && *pb)
+ {
+ wchar_t ca = *pa;
+ wchar_t cb = *pb;
+ if (ca < cb)
+ return -1;
+ else if (ca > cb)
+ return 1;
+ pa++;
+ pb++;
+ }
+ if (*pa)
+ return 1;
+ else if (*pb)
+ return -1;
+ else
+ return 0;
+#endif
+}
+
+int OVR_CDECL OVR_wcsicmp(const wchar_t* a, const wchar_t* b)
+{
+#if defined(OVR_OS_WIN32)
+#if defined(OVR_CC_MSVC) && (OVR_CC_MSVC >= 1400)
+ return ::_wcsicmp(a, b);
+#else
+ return ::wcsicmp(a, b);
+#endif
+#elif defined(OVR_OS_MAC) || defined(__CYGWIN__) || defined(OVR_OS_ANDROID) || defined(OVR_OS_IPHONE)
+ // not supported, use custom implementation
+ const wchar_t *pa = a, *pb = b;
+ while (*pa && *pb)
+ {
+ wchar_t ca = OVR_towlower(*pa);
+ wchar_t cb = OVR_towlower(*pb);
+ if (ca < cb)
+ return -1;
+ else if (ca > cb)
+ return 1;
+ pa++;
+ pb++;
+ }
+ if (*pa)
+ return 1;
+ else if (*pb)
+ return -1;
+ else
+ return 0;
+#else
+ return wcscasecmp(a, b);
+#endif
+}
+
+// This function is not inline because of dependency on <locale.h>
+double OVR_CDECL OVR_strtod(const char* string, char** tailptr)
+{
+#if !defined(OVR_OS_ANDROID)
+ const char s = *localeconv()->decimal_point;
+
+ if (s != '.')
+ {
+ char buffer[347 + 1];
+
+ OVR_strcpy(buffer, sizeof(buffer), string);
+
+ for (char* c = buffer; *c != '\0'; ++c)
+ {
+ if (*c == '.')
+ {
+ *c = s;
+ break;
+ }
+ }
+
+ return strtod(buffer, tailptr);
+ }
+#endif
+
+ return strtod(string, tailptr);
+}
+
+
+#ifndef OVR_NO_WCTYPE
+
+//// Use this class to generate Unicode bitsets. For example:
+////
+//// UnicodeBitSet bitSet;
+//// for(unsigned i = 0; i < 65536; ++i)
+//// {
+//// if (iswalpha(i))
+//// bitSet.Set(i);
+//// }
+//// bitSet.Dump();
+////
+////---------------------------------------------------------------
+//class UnicodeBitSet
+//{
+//public:
+// UnicodeBitSet()
+// {
+// memset(Offsets, 0, sizeof(Offsets));
+// memset(Bits, 0, sizeof(Bits));
+// }
+//
+// void Set(unsigned bit) { Bits[bit >> 8][(bit >> 4) & 15] |= 1 << (bit & 15); }
+//
+// void Dump()
+// {
+// unsigned i, j;
+// unsigned offsetCount = 0;
+// for(i = 0; i < 256; ++i)
+// {
+// if (isNull(i)) Offsets[i] = 0;
+// else
+// if (isFull(i)) Offsets[i] = 1;
+// else Offsets[i] = UInt16(offsetCount++ * 16 + 256);
+// }
+// for(i = 0; i < 16; ++i)
+// {
+// for(j = 0; j < 16; ++j)
+// {
+// printf("%5u,", Offsets[i*16+j]);
+// }
+// printf("\n");
+// }
+// for(i = 0; i < 256; ++i)
+// {
+// if (Offsets[i] > 255)
+// {
+// for(j = 0; j < 16; j++)
+// {
+// printf("%5u,", Bits[i][j]);
+// }
+// printf("\n");
+// }
+// }
+// }
+//
+//private:
+// bool isNull(unsigned n) const
+// {
+// const UInt16* p = Bits[n];
+// for(unsigned i = 0; i < 16; ++i)
+// if (p[i] != 0) return false;
+// return true;
+// }
+//
+// bool isFull(unsigned n) const
+// {
+// const UInt16* p = Bits[n];
+// for(unsigned i = 0; i < 16; ++i)
+// if (p[i] != 0xFFFF) return false;
+// return true;
+// }
+//
+// UInt16 Offsets[256];
+// UInt16 Bits[256][16];
+//};
+
+
+const UInt16 UnicodeAlnumBits[] = {
+ 256, 1, 272, 288, 304, 320, 336, 352, 0, 368, 384, 400, 416, 432, 448, 464,
+ 480, 496, 512, 528, 544, 1, 560, 576, 592, 0, 0, 0, 0, 0, 608, 624,
+ 640, 656, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 672, 688, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 704, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 720,
+ 1, 1, 1, 1, 736, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 752, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 768, 784, 1, 800, 816, 832,
+ 0, 0, 0, 1023,65534, 2047,65534, 2047, 0, 0, 0, 524,65535,65407,65535,65407,
+65535,65535,65532, 15, 0,65535,65535,65535,65535,65535,16383,63999, 3, 0,16415, 0,
+ 0, 0, 0, 0, 32, 0, 0, 1024,55104,65535,65531,65535,32767,64767,65535, 15,
+65535,65535,65535,65535,65535,65535,65535,65535,61443,65535,65535,65535, 6559,65535,65535, 831,
+ 0, 0, 0,65534,65535, 639,65534,65535, 255, 0, 0, 0, 0,65535, 2047, 7,
+ 0, 0,65534, 2047,65534, 63, 1023,65535,65535,65535,65535,65535,65535, 8175, 8702, 8191,
+ 0,65535, 8191,65535, 0, 0, 0, 0,65535,65535,65535, 1, 0, 0, 0, 0,
+65518,65535,65535,58367, 8191,65281,65487, 0,40942,65529,65023,50117, 6559,45184,65487, 3,
+34788,65529,65023,50029, 6535,24064,65472, 31,45038,65531,65023,58349, 7103, 1,65473, 0,
+40942,65529,65023,58317, 6543,45248,65475, 0,51180,54845,50968,50111, 7623, 128,65408, 0,
+57326,65533,65023,50159, 7647, 96,65475, 0,57324,65533,65023,50159, 7647,16480,65475, 0,
+57324,65533,65023,50175, 7631, 128,65475, 0,65516,64639,65535,12283,32895,65375, 0, 12,
+65534,65535,65535, 2047,32767, 1023, 0, 0, 9622,65264,60590,15359, 8223,13311, 0, 0,
+ 1, 0, 1023, 0,65279,65535, 2047,65534, 3843,65279,65535, 8191, 0, 0, 0, 0,
+65535,65535,63227, 327, 1023, 1023, 0, 0, 0, 0,65535,65535, 63,65535,65535, 127,
+65535,65535,65535,65535,65535,33791,65535,65535,65535,65535,65287,65535,65535,65535,65535, 1023,
+65407,65535,65535,65535,15743,15743,65535,65535,15743,65535,32767,32573,32573,65407,32767,65535,
+32767,32573,65535,65535,65407, 2047,65024, 3, 0, 0,65535,65535,65535,65535,65535, 31,
+65534,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,
+65535,65535,65535,65535,65535,65535,40959, 127,65534, 2047,65535,65535,65535,65535, 2047, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,65535,65535,65535,65535, 511, 0, 1023, 0,
+ 0, 1023,65535,65535,65527,65535,65535, 255,65535,65535, 1023, 0, 0, 0, 0, 0,
+65535,65535,65535,65535,65535,65535,65535,65535,65535, 4095,65535,65535,65535,65535,65535, 1023,
+65535,16191,65535,65535,16191,43775,65535,16383,65535,65535,65535,24543, 8156, 4047, 8191, 8156,
+ 0, 0, 0, 0, 0, 0, 0,32768, 0, 0, 0, 0, 0, 0, 0, 0,
+64644,15919,48464, 1019, 0, 0,65535,65535, 15, 0, 0, 0, 0, 0, 0, 0,
+ 192, 0, 1022, 1792,65534,65535,65535,65535,65535, 31,65534,65535,65535,65535,65535, 2047,
+65504,65535, 8191,65534,65535,65535,65535,65535,32767, 0,65535, 255, 0, 0, 0, 0,
+65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535, 63, 0, 0, 0, 0,
+65535,65535,65535,65535,65535,65535,65535,65535,65535,65535, 63, 0, 0, 0, 0, 0,
+65535,65535,65535,65535,65535,65535,65535,65535, 8191, 0, 0, 0, 0, 0, 0, 0,
+65535,65535,65535,65535,65535,65535,65535,65535,65535,65535, 15, 0, 0, 0, 0, 0,
+65535,65535,16383, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 127,41208,65023,24447,65499,65535,65535,65535,65535,65535,65535, 3, 0,65528,65535,65535,
+65535,65535,65535,16383, 0,65535,65535,65535,65535,65532,65535,65535, 255, 0, 0, 4095,
+ 0, 0, 0, 0, 0, 0, 0,65495,65535,65535,65535,65535,65535,65535,65535, 8191,
+ 0, 1023,65534, 2047,65534, 2047,65472,65534,65535,16383,65535,32767,64764, 7420, 0, 0};
+
+const UInt16 UnicodeAlphaBits[] = {
+ 256, 1, 272, 288, 304, 320, 336, 352, 0, 368, 384, 400, 416, 432, 448, 464,
+ 480, 496, 512, 528, 544, 1, 560, 576, 592, 0, 0, 0, 0, 0, 608, 624,
+ 640, 656, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 672, 688, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 704, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 720,
+ 1, 1, 1, 1, 736, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 752, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 768, 784, 1, 800, 816, 832,
+ 0, 0, 0, 0,65534, 2047,65534, 2047, 0, 0, 0, 0,65535,65407,65535,65407,
+65535,65535,65532, 15, 0,65535,65535,65535,65535,65535,16383,63999, 3, 0,16415, 0,
+ 0, 0, 0, 0, 32, 0, 0, 1024,55104,65535,65531,65535,32767,64767,65535, 15,
+65535,65535,65535,65535,65535,65535,65535,65535,61443,65535,65535,65535, 6559,65535,65535, 831,
+ 0, 0, 0,65534,65535, 639,65534,65535, 255, 0, 0, 0, 0,65535, 2047, 7,
+ 0, 0,65534, 2047,65534, 63, 0,65535,65535,65535,65535,65535,65535, 8175, 8702, 7168,
+ 0,65535, 8191,65535, 0, 0, 0, 0,65535,65535,65535, 1, 0, 0, 0, 0,
+65518,65535,65535,58367, 8191,65281, 15, 0,40942,65529,65023,50117, 6559,45184, 15, 3,
+34788,65529,65023,50029, 6535,24064, 0, 31,45038,65531,65023,58349, 7103, 1, 1, 0,
+40942,65529,65023,58317, 6543,45248, 3, 0,51180,54845,50968,50111, 7623, 128, 0, 0,
+57326,65533,65023,50159, 7647, 96, 3, 0,57324,65533,65023,50159, 7647,16480, 3, 0,
+57324,65533,65023,50175, 7631, 128, 3, 0,65516,64639,65535,12283,32895,65375, 0, 12,
+65534,65535,65535, 2047,32767, 0, 0, 0, 9622,65264,60590,15359, 8223,12288, 0, 0,
+ 1, 0, 0, 0,65279,65535, 2047,65534, 3843,65279,65535, 8191, 0, 0, 0, 0,
+65535,65535,63227, 327, 0, 1023, 0, 0, 0, 0,65535,65535, 63,65535,65535, 127,
+65535,65535,65535,65535,65535,33791,65535,65535,65535,65535,65287,65535,65535,65535,65535, 1023,
+65407,65535,65535,65535,15743,15743,65535,65535,15743,65535,32767,32573,32573,65407,32767,65535,
+32767,32573,65535,65535,65407, 2047, 0, 0, 0, 0,65535,65535,65535,65535,65535, 31,
+65534,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,
+65535,65535,65535,65535,65535,65535,40959, 127,65534, 2047,65535,65535,65535,65535, 2047, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,65535,65535,65535,65535, 511, 0, 0, 0,
+ 0, 0,65535,65535,65527,65535,65535, 255,65535,65535, 1023, 0, 0, 0, 0, 0,
+65535,65535,65535,65535,65535,65535,65535,65535,65535, 4095,65535,65535,65535,65535,65535, 1023,
+65535,16191,65535,65535,16191,43775,65535,16383,65535,65535,65535,24543, 8156, 4047, 8191, 8156,
+ 0, 0, 0, 0, 0, 0, 0,32768, 0, 0, 0, 0, 0, 0, 0, 0,
+64644,15919,48464, 1019, 0, 0,65535,65535, 15, 0, 0, 0, 0, 0, 0, 0,
+ 192, 0, 1022, 1792,65534,65535,65535,65535,65535, 31,65534,65535,65535,65535,65535, 2047,
+65504,65535, 8191,65534,65535,65535,65535,65535,32767, 0,65535, 255, 0, 0, 0, 0,
+65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535, 63, 0, 0, 0, 0,
+65535,65535,65535,65535,65535,65535,65535,65535,65535,65535, 63, 0, 0, 0, 0, 0,
+65535,65535,65535,65535,65535,65535,65535,65535, 8191, 0, 0, 0, 0, 0, 0, 0,
+65535,65535,65535,65535,65535,65535,65535,65535,65535,65535, 15, 0, 0, 0, 0, 0,
+65535,65535,16383, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 127,41208,65023,24447,65499,65535,65535,65535,65535,65535,65535, 3, 0,65528,65535,65535,
+65535,65535,65535,16383, 0,65535,65535,65535,65535,65532,65535,65535, 255, 0, 0, 4095,
+ 0, 0, 0, 0, 0, 0, 0,65495,65535,65535,65535,65535,65535,65535,65535, 8191,
+ 0, 0,65534, 2047,65534, 2047,65472,65534,65535,16383,65535,32767,64764, 7420, 0, 0};
+
+const UInt16 UnicodeDigitBits[] = {
+ 256, 0, 0, 0, 0, 0, 272, 0, 0, 288, 304, 320, 336, 352, 368, 384,
+ 400, 0, 0, 416, 0, 0, 0, 432, 448, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 464,
+ 0, 0, 0, 1023, 0, 0, 0, 0, 0, 0, 0, 524, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 1023, 0, 0, 0, 0, 0, 0, 0, 0, 1023,
+ 0, 0, 0, 0, 0, 0,65472, 0, 0, 0, 0, 0, 0, 0,65472, 0,
+ 0, 0, 0, 0, 0, 0,65472, 0, 0, 0, 0, 0, 0, 0,65472, 0,
+ 0, 0, 0, 0, 0, 0,65472, 0, 0, 0, 0, 0, 0, 0,65408, 0,
+ 0, 0, 0, 0, 0, 0,65472, 0, 0, 0, 0, 0, 0, 0,65472, 0,
+ 0, 0, 0, 0, 0, 0,65472, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 1023, 0, 0, 0, 0, 0, 0, 0, 1023, 0, 0,
+ 0, 0, 1023, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 1023, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,65024, 3, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1023, 0,
+ 0, 1023, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 1023, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+
+const UInt16 UnicodeSpaceBits[] = {
+ 256, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 272, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 288, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 304, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+15872, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0,
+ 4095, 0,33536, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+
+const UInt16 UnicodeXDigitBits[] = {
+ 256, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 272,
+ 0, 0, 0, 1023, 126, 0, 126, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 1023, 126, 0, 126, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+
+// Uncomment if necessary
+//const UInt16 UnicodeCntrlBits[] = {
+// 256, 0, 0, 0, 0, 0, 0, 272, 0, 0, 0, 0, 0, 0, 0, 0,
+// 0, 0, 0, 0, 0, 0, 0, 0, 288, 0, 0, 0, 0, 0, 0, 0,
+// 304, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+// 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+// 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+// 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+// 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+// 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+// 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+// 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+// 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+// 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+// 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+// 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+// 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+// 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 320, 336,
+//65535,65535, 0, 0, 0, 0, 0,32768,65535,65535, 0, 0, 0, 0, 0, 0,
+//32768, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+//30720, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+//61440, 0,31744, 0, 0, 0,64512, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+// 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,32768,
+// 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3584};
+//
+//const UInt16 UnicodeGraphBits[] = {
+// 256, 1, 272, 288, 304, 320, 336, 352, 0, 368, 384, 400, 416, 432, 448, 464,
+// 480, 496, 512, 528, 544, 1, 560, 576, 592, 0, 0, 0, 0, 0, 608, 624,
+// 640, 656, 0, 672, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+// 688, 704, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+// 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 720, 1, 1,
+// 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+// 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+// 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+// 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+// 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 736,
+// 1, 1, 1, 1, 752, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1,
+// 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+// 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+// 1, 1, 1, 1, 1, 1, 1, 768, 0, 0, 0, 0, 0, 0, 0, 0,
+// 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+// 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 784, 800, 1, 816, 832, 848,
+// 0, 0,65534,65535,65535,65535,65535,32767, 0, 0,65534,65535,65535,65535,65535,65535,
+//65535,65535,65532, 15, 0,65535,65535,65535,65535,65535,16383,63999, 3, 0,16415, 0,
+// 0, 0, 0, 0, 32, 0, 0,17408,55232,65535,65531,65535,32767,64767,65535, 15,
+//65535,65535,65535,65535,65535,65535,65535,65535,61443,65535,65535,65535, 6559,65535,65535, 831,
+// 0, 0, 0,65534,65535,65151,65534,65535, 1791, 0, 0,16384, 9,65535, 2047, 31,
+// 4096,34816,65534, 2047,65534, 63,16383,65535,65535,65535,65535,65535,65535, 8191, 8702, 8191,
+//16383,65535, 8191,65535, 0, 0, 0, 0,65535,65535,65535, 1, 0, 0, 0, 0,
+//65518,65535,65535,58367, 8191,65281,65535, 1,40942,65529,65023,50117, 6559,45184,65487, 3,
+//34788,65529,65023,50029, 6535,24064,65472, 31,45038,65531,65023,58349, 7103, 1,65473, 0,
+//40942,65529,65023,58317, 6543,45248,65475, 0,51180,54845,50968,50111, 7623, 128,65408, 0,
+//57326,65533,65023,50159, 7647, 96,65475, 0,57324,65533,65023,50159, 7647,16480,65475, 0,
+//57324,65533,65023,50175, 7631, 128,65475, 0,65516,64639,65535,12283,32895,65375, 0, 28,
+//65534,65535,65535, 2047,65535, 4095, 0, 0, 9622,65264,60590,15359, 8223,13311, 0, 0,
+//65521, 7, 1023,15360,65279,65535, 2047,65534, 3875,65279,65535, 8191, 0, 0, 0, 0,
+//65535,65535,63227, 327,65535, 1023, 0, 0, 0, 0,65535,65535, 63,65535,65535, 2175,
+//65535,65535,65535,65535,65535,33791,65535,65535,65535,65535,65287,65535,65535,65535,65535, 1023,
+//65407,65535,65535,65535,15743,15743,65535,65535,15743,65535,32767,32573,32573,65407,32767,65535,
+//32767,32573,65535,65535,65407, 2047,65534, 3, 0, 0,65535,65535,65535,65535,65535, 31,
+//65534,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,
+//65535,65535,65535,65535,65535,65535,65535, 127,65534, 8191,65535,65535,65535,65535,16383, 0,
+// 0, 0, 0, 0, 0, 0, 0, 0,65535,65535,65535,65535, 511, 6128, 1023, 0,
+// 2047, 1023,65535,65535,65527,65535,65535, 255,65535,65535, 1023, 0, 0, 0, 0, 0,
+//65535,65535,65535,65535,65535,65535,65535,65535,65535, 4095,65535,65535,65535,65535,65535, 1023,
+//65535,16191,65535,65535,16191,43775,65535,16383,65535,65535,65535,24543, 8156, 4047, 8191, 8156,
+// 0,65535, 255,65535,16239, 0, 0,57344,24576, 0, 0, 0, 0, 0, 0, 0,
+//64644,15919,48464, 1019, 0, 0,65535,65535, 15, 0, 0, 0, 0, 0, 0, 0,
+// 0, 0, 1536, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+//65486,65523, 1022, 1793,65534,65535,65535,65535,65535, 31,65534,65535,65535,65535,65535, 4095,
+//65504,65535, 8191,65534,65535,65535,65535,65535,32767, 0,65535, 255, 0, 0, 0, 0,
+//65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535, 63, 0, 0, 0, 0,
+//65535,65535,65535,65535,65535,65535,65535,65535,65535,65535, 63, 0, 0, 0, 0, 0,
+//65535,65535,65535,65535,65535,65535,65535,65535, 8191, 0, 0, 0, 0, 0, 0, 0,
+//65535,65535,65535,65535,65535,65535,65535,65535,65535,65535, 15, 0, 0, 0, 0, 0,
+//65535,65535,16383, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+// 127,41208,65023,24447,65499,65535,65535,65535,65535,65535,65535, 3, 0,65528,65535,65535,
+//65535,65535,65535,65535, 0,65535,65535,65535,65535,65532,65535,65535, 255, 0, 0, 4095,
+// 0, 0, 0,65535,65055,65527, 3339,65495,65535,65535,65535,65535,65535,65535,65535, 8191,
+//63470,36863,65535,49151,65534,12287,65534,65534,65535,16383,65535,32767,64764, 7420, 0, 0};
+//
+//const UInt16 UnicodePrintBits[] = {
+// 256, 1, 272, 288, 304, 320, 336, 352, 0, 368, 384, 400, 416, 432, 448, 464,
+// 480, 496, 512, 528, 544, 1, 560, 576, 592, 0, 0, 0, 0, 0, 608, 624,
+// 640, 656, 0, 672, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+// 688, 704, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+// 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 720, 1, 1,
+// 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+// 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+// 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+// 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+// 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 736,
+// 1, 1, 1, 1, 752, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1,
+// 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+// 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+// 1, 1, 1, 1, 1, 1, 1, 768, 0, 0, 0, 0, 0, 0, 0, 0,
+// 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+// 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 784, 800, 1, 816, 832, 848,
+// 512, 0,65535,65535,65535,65535,65535,32767, 0, 0,65535,65535,65535,65535,65535,65535,
+//65535,65535,65532, 15, 0,65535,65535,65535,65535,65535,16383,63999, 3, 0,16415, 0,
+// 0, 0, 0, 0, 32, 0, 0,17408,55232,65535,65531,65535,32767,64767,65535, 15,
+//65535,65535,65535,65535,65535,65535,65535,65535,61443,65535,65535,65535, 6559,65535,65535, 831,
+// 0, 0, 0,65534,65535,65151,65534,65535, 1791, 0, 0,16384, 9,65535, 2047, 31,
+// 4096,34816,65534, 2047,65534, 63,16383,65535,65535,65535,65535,65535,65535, 8191, 8702, 8191,
+//16383,65535, 8191,65535, 0, 0, 0, 0,65535,65535,65535, 1, 0, 0, 0, 0,
+//65518,65535,65535,58367, 8191,65281,65535, 1,40942,65529,65023,50117, 6559,45184,65487, 3,
+//34788,65529,65023,50029, 6535,24064,65472, 31,45038,65531,65023,58349, 7103, 1,65473, 0,
+//40942,65529,65023,58317, 6543,45248,65475, 0,51180,54845,50968,50111, 7623, 128,65408, 0,
+//57326,65533,65023,50159, 7647, 96,65475, 0,57324,65533,65023,50159, 7647,16480,65475, 0,
+//57324,65533,65023,50175, 7631, 128,65475, 0,65516,64639,65535,12283,32895,65375, 0, 28,
+//65534,65535,65535, 2047,65535, 4095, 0, 0, 9622,65264,60590,15359, 8223,13311, 0, 0,
+//65521, 7, 1023,15360,65279,65535, 2047,65534, 3875,65279,65535, 8191, 0, 0, 0, 0,
+//65535,65535,63227, 327,65535, 1023, 0, 0, 0, 0,65535,65535, 63,65535,65535, 2175,
+//65535,65535,65535,65535,65535,33791,65535,65535,65535,65535,65287,65535,65535,65535,65535, 1023,
+//65407,65535,65535,65535,15743,15743,65535,65535,15743,65535,32767,32573,32573,65407,32767,65535,
+//32767,32573,65535,65535,65407, 2047,65534, 3, 0, 0,65535,65535,65535,65535,65535, 31,
+//65534,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,
+//65535,65535,65535,65535,65535,65535,65535, 127,65534, 8191,65535,65535,65535,65535,16383, 0,
+// 0, 0, 0, 0, 0, 0, 0, 0,65535,65535,65535,65535, 511, 6128, 1023, 0,
+// 2047, 1023,65535,65535,65527,65535,65535, 255,65535,65535, 1023, 0, 0, 0, 0, 0,
+//65535,65535,65535,65535,65535,65535,65535,65535,65535, 4095,65535,65535,65535,65535,65535, 1023,
+//65535,16191,65535,65535,16191,43775,65535,16383,65535,65535,65535,24543, 8156, 4047, 8191, 8156,
+// 0,65535, 255,65535,16239, 0, 0,57344,24576, 0, 0, 0, 0, 0, 0, 0,
+//64644,15919,48464, 1019, 0, 0,65535,65535, 15, 0, 0, 0, 0, 0, 0, 0,
+// 0, 0, 1536, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+//65487,65523, 1022, 1793,65534,65535,65535,65535,65535, 31,65534,65535,65535,65535,65535, 4095,
+//65504,65535, 8191,65534,65535,65535,65535,65535,32767, 0,65535, 255, 0, 0, 0, 0,
+//65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535, 63, 0, 0, 0, 0,
+//65535,65535,65535,65535,65535,65535,65535,65535,65535,65535, 63, 0, 0, 0, 0, 0,
+//65535,65535,65535,65535,65535,65535,65535,65535, 8191, 0, 0, 0, 0, 0, 0, 0,
+//65535,65535,65535,65535,65535,65535,65535,65535,65535,65535, 15, 0, 0, 0, 0, 0,
+//65535,65535,16383, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+// 127,41208,65023,24447,65499,65535,65535,65535,65535,65535,65535, 3, 0,65528,65535,65535,
+//65535,65535,65535,65535, 0,65535,65535,65535,65535,65532,65535,65535, 255, 0, 0, 4095,
+// 0, 0, 0,65535,65055,65527, 3339,65495,65535,65535,65535,65535,65535,65535,65535,40959,
+//63470,36863,65535,49151,65534,12287,65534,65534,65535,16383,65535,32767,64764, 7420, 0, 0};
+//
+//const UInt16 UnicodePunctBits[] = {
+// 256, 0, 0, 272, 0, 288, 304, 320, 0, 336, 0, 0, 0, 352, 368, 384,
+// 400, 0, 0, 416, 0, 0, 432, 448, 464, 0, 0, 0, 0, 0, 0, 0,
+// 480, 0, 0, 496, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+// 512, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+// 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+// 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+// 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+// 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+// 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+// 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+// 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+// 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+// 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+// 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+// 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+// 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 528, 544, 560,
+// 0, 0,65534,64512, 1,63488, 1,30720, 0, 0,65534,65535, 0, 128, 0, 128,
+// 0, 0, 0, 0, 0, 0, 0,16384, 128, 0, 0, 0, 0, 0, 0, 0,
+// 0, 0, 0, 0, 0,64512, 0, 0, 1536, 0, 0,16384, 9, 0, 0, 24,
+// 4096,34816, 0, 0, 0, 0,15360, 0, 0, 0, 0, 0, 0, 16, 0, 0,
+//16383, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+// 0, 0, 0, 0, 0, 0, 48, 1, 0, 0, 0, 0, 0, 0, 0, 0,
+// 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16,
+// 0, 0, 0, 0,32768, 3072, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+//65520, 7, 0,15360, 0, 0, 0, 0, 32, 0, 0, 0, 0, 0, 0, 0,
+// 0, 0, 0, 0,64512, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2048,
+// 0, 0, 0, 0, 0, 0, 510, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+// 0, 0, 0, 0, 0, 0,24576, 0, 0, 6144, 0, 0, 0, 0,14336, 0,
+// 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6128, 0, 0,
+// 2047, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+// 0,65535, 255,65535,16239, 0, 0,24576,24576, 0, 0, 0, 0, 0, 0, 0,
+// 0, 0, 1536, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+//65294,65523, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2048,
+// 0, 0, 0,49152, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+// 0, 0, 0,65535,65055,65527, 3339, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+//63470,35840, 1,47104, 0,10240, 62, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+//
+//const UInt16 UnicodeLowerBits[] = {
+// 256, 272, 288, 304, 320, 336, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+// 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 352, 368,
+// 384, 400, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+// 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+// 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+// 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+// 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+// 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+// 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+// 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+// 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+// 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+// 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+// 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+// 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+// 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 416, 0, 0, 0, 432,
+// 0, 0, 0, 0, 0, 0,65534, 2047, 0, 0, 0, 0, 0,32768,65535,65407,
+//43690,43690,43690,21930,43861,43690,43690,54442,12585,20004,11562,58961,23392,46421,43690,43565,
+//43690,43690,43688, 10, 0,65535,65535,65535,65535,65535,16383, 0, 0, 0, 0, 0,
+// 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,61440,65535,32767,43235,43690, 15,
+// 0, 0, 0,65535,65535,65535,43690,43690,40962,43690,43690,43690, 4372,43690,43690, 554,
+// 0, 0, 0, 0, 0, 0,65534,65535, 255, 0, 0, 0, 0, 0, 0, 0,
+//43690,43690,43690,43690,43690,43690,43690,43690,43690, 4074,43690,43690,43690,43690,43690, 682,
+// 255, 63, 255, 255, 63, 255, 255,16383,65535,65535,65535,20703, 4316, 207, 255, 4316,
+// 0, 0, 0, 0, 0, 0, 0,32768, 0, 0, 0, 0, 0, 0, 0, 0,
+//50176, 8,32768, 528, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+// 127, 248, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+// 0, 0, 0, 0,65534, 2047, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+//
+//const UInt16 UnicodeUpperBits[] = {
+// 256, 272, 288, 304, 320, 336, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+// 352, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 368, 384,
+// 0, 400, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+// 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+// 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+// 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+// 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+// 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+// 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+// 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+// 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+// 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+// 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+// 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+// 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+// 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 416,
+// 0, 0, 0, 0,65534, 2047, 0, 0, 0, 0, 0, 0,65535,32639, 0, 0,
+//21845,21845,21845,43605,21674,21845,21845,11093,52950,45531,53973, 4526,44464,19114,21845,21974,
+//21845,21845,21844, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+// 0, 0, 0, 0, 0, 0, 0, 0,55104,65534, 4091, 0, 0,21532,21845, 0,
+//65535,65535,65535, 0, 0, 0,21845,21845,20481,21845,21845,21845, 2187,21845,21845, 277,
+// 0, 0, 0,65534,65535, 127, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+// 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,65535,65535, 63, 0, 0, 0,
+//21845,21845,21845,21845,21845,21845,21845,21845,21845, 21,21845,21845,21845,21845,21845, 341,
+//65280,16128,65280,65280,16128,43520,65280, 0,65280,65280,65280, 7936, 7936, 3840, 7936, 7936,
+//14468,15911,15696, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+// 0, 0,65534, 2047, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+
+
+// MA: March 19, 2010
+// Modified ToUpper and ToLower tables to match values expected by AS3 tests.
+// ToLower modifications:
+// 304 -> 105
+// 1024 -> 1104 *
+// 1037 -> 1117 *
+// UoUpper modifications:
+// 255 -> 376
+// 305 -> 73
+// 383 -> 83
+// 1104 -> 1024 *
+// 1117 -> 1037 *
+// Entries marked with a '*' don't make complete sense based on Unicode manual, although
+// they match AS3.
+
+
+static const UInt16 UnicodeToUpperBits[] = {
+ 256, 272, 288, 304, 320, 336, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 352, 368,
+ 0, 384, 0, 0, 400, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 416,
+ 0, 0, 0, 0, 0, 0,65534, 2047, 0, 0, 0, 0, 0, 0,65535,65407,
+43690,43690,43690,21674,43349,43690,43690,54442, 4392, 516, 8490, 8785,21056,46421,43690,43048, // MA: Modified for AS3.
+43690, 170, 0, 0, 0, 2776,33545, 36, 3336, 4, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,61440,65534,32767, 0,43688, 0,
+ 0, 0, 0,65535,65535,65535,43690,43690, 2,43690,43690,43690, 4372,43690,35498, 554, // MA: Modified for AS3.
+ 0, 0, 0, 0, 0, 0,65534,65535, 127, 0, 0, 0, 0, 0, 0, 0,
+43690,43690,43690,43690,43690,43690,43690,43690,43690, 42,43690,43690,43690,43690,43690, 682,
+ 255, 63, 255, 255, 63, 170, 255,16383, 0, 0, 0, 3, 0, 3, 35, 0,
+ 0, 0, 0, 0, 0, 0, 0,65535, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,65535, 1023, 0,
+ 0, 0, 0, 0,65534, 2047, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+
+static const UInt16 UnicodeToLowerBits[] = {
+ 256, 272, 288, 304, 320, 336, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 352, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 368, 384,
+ 0, 400, 0, 0, 416, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 432,
+ 0, 0, 0, 0,65534, 2047, 0, 0, 0, 0, 0, 0,65535,32639, 0, 0,
+21845,21845,21845,43605,21674,21845,21845,11093,52950,45531,53909, 4526,42128,19114,21845,21522,// MA: Modidied for AS3.
+21845, 85, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,55104,65534, 4091, 0, 0, 0,21844, 0,
+65535,65535,65535, 0, 0, 0,21845,21845, 1,21845,21845,21845, 2186,21845,17749, 277,
+ 0, 0, 0,65534,65535, 127, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,65535,65535, 63, 0, 0, 0,
+21845,21845,21845,21845,21845,21845,21845,21845,21845, 21,21845,21845,21845,21845,21845, 341,
+65280,16128,65280,65280,16128,43520,65280, 0, 0, 0, 0, 3840, 3840, 3840, 7936, 3840,
+ 0, 0, 0, 0, 0, 0,65535, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,65472,65535, 0, 0, 0,
+ 0, 0,65534, 2047, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+
+struct GUnicodePairType
+{
+ UInt16 Key, Value;
+};
+
+static inline bool CmpUnicodeKey(const GUnicodePairType& a, UInt16 key)
+{
+ return a.Key < key;
+}
+
+static const GUnicodePairType UnicodeToUpperTable[] = {
+{ 97, 65}, { 98, 66}, { 99, 67}, { 100, 68}, { 101, 69}, { 102, 70}, { 103, 71},
+{ 104, 72}, { 105, 73}, { 106, 74}, { 107, 75}, { 108, 76}, { 109, 77}, { 110, 78},
+{ 111, 79}, { 112, 80}, { 113, 81}, { 114, 82}, { 115, 83}, { 116, 84}, { 117, 85},
+{ 118, 86}, { 119, 87}, { 120, 88}, { 121, 89}, { 122, 90}, { 224, 192}, { 225, 193},
+{ 226, 194}, { 227, 195}, { 228, 196}, { 229, 197}, { 230, 198}, { 231, 199}, { 232, 200},
+{ 233, 201}, { 234, 202}, { 235, 203}, { 236, 204}, { 237, 205}, { 238, 206}, { 239, 207},
+{ 240, 208}, { 241, 209}, { 242, 210}, { 243, 211}, { 244, 212}, { 245, 213}, { 246, 214},
+{ 248, 216}, { 249, 217}, { 250, 218}, { 251, 219}, { 252, 220}, { 253, 221}, { 254, 222},
+{ 255, 376}, { 257, 256}, { 259, 258}, { 261, 260}, { 263, 262}, { 265, 264}, { 267, 266},
+{ 269, 268}, { 271, 270}, { 273, 272}, { 275, 274}, { 277, 276}, { 279, 278}, { 281, 280},
+{ 283, 282}, { 285, 284}, { 287, 286}, { 289, 288}, { 291, 290}, { 293, 292}, { 295, 294},
+{ 297, 296}, { 299, 298}, { 301, 300}, { 303, 302}, { 305, 73}, { 307, 306}, { 309, 308}, { 311, 310},
+{ 314, 313}, { 316, 315}, { 318, 317}, { 320, 319}, { 322, 321}, { 324, 323}, { 326, 325},
+{ 328, 327}, { 331, 330}, { 333, 332}, { 335, 334}, { 337, 336}, { 339, 338}, { 341, 340},
+{ 343, 342}, { 345, 344}, { 347, 346}, { 349, 348}, { 351, 350}, { 353, 352}, { 355, 354},
+{ 357, 356}, { 359, 358}, { 361, 360}, { 363, 362}, { 365, 364}, { 367, 366}, { 369, 368},
+{ 371, 370}, { 373, 372}, { 375, 374}, { 378, 377}, { 380, 379}, { 382, 381}, { 383, 83}, { 387, 386},
+{ 389, 388}, { 392, 391}, { 396, 395}, { 402, 401}, { 409, 408}, { 417, 416}, { 419, 418},
+{ 421, 420}, { 424, 423}, { 429, 428}, { 432, 431}, { 436, 435}, { 438, 437}, { 441, 440},
+{ 445, 444}, { 454, 452}, { 457, 455}, { 460, 458}, { 462, 461}, { 464, 463}, { 466, 465},
+{ 468, 467}, { 470, 469}, { 472, 471}, { 474, 473}, { 476, 475}, { 477, 398}, { 479, 478},
+{ 481, 480}, { 483, 482}, { 485, 484}, { 487, 486}, { 489, 488}, { 491, 490}, { 493, 492},
+{ 495, 494}, { 499, 497}, { 501, 500}, { 507, 506}, { 509, 508}, { 511, 510}, { 513, 512},
+{ 515, 514}, { 517, 516}, { 519, 518}, { 521, 520}, { 523, 522}, { 525, 524}, { 527, 526},
+{ 529, 528}, { 531, 530}, { 533, 532}, { 535, 534}, { 595, 385}, { 596, 390}, { 598, 393},
+{ 599, 394}, { 601, 399}, { 603, 400}, { 608, 403}, { 611, 404}, { 616, 407}, { 617, 406},
+{ 623, 412}, { 626, 413}, { 629, 415}, { 643, 425}, { 648, 430}, { 650, 433}, { 651, 434},
+{ 658, 439}, { 940, 902}, { 941, 904}, { 942, 905}, { 943, 906}, { 945, 913}, { 946, 914},
+{ 947, 915}, { 948, 916}, { 949, 917}, { 950, 918}, { 951, 919}, { 952, 920}, { 953, 921},
+{ 954, 922}, { 955, 923}, { 956, 924}, { 957, 925}, { 958, 926}, { 959, 927}, { 960, 928},
+{ 961, 929}, { 962, 931}, { 963, 931}, { 964, 932}, { 965, 933}, { 966, 934}, { 967, 935},
+{ 968, 936}, { 969, 937}, { 970, 938}, { 971, 939}, { 972, 908}, { 973, 910}, { 974, 911},
+{ 995, 994}, { 997, 996}, { 999, 998}, { 1001, 1000}, { 1003, 1002}, { 1005, 1004}, { 1007, 1006},
+{ 1072, 1040}, { 1073, 1041}, { 1074, 1042}, { 1075, 1043}, { 1076, 1044}, { 1077, 1045}, { 1078, 1046},
+{ 1079, 1047}, { 1080, 1048}, { 1081, 1049}, { 1082, 1050}, { 1083, 1051}, { 1084, 1052}, { 1085, 1053},
+{ 1086, 1054}, { 1087, 1055}, { 1088, 1056}, { 1089, 1057}, { 1090, 1058}, { 1091, 1059}, { 1092, 1060},
+{ 1093, 1061}, { 1094, 1062}, { 1095, 1063}, { 1096, 1064}, { 1097, 1065}, { 1098, 1066}, { 1099, 1067},
+{ 1100, 1068}, { 1101, 1069}, { 1102, 1070}, { 1103, 1071}, { 1104, 1024}, { 1105, 1025}, { 1106, 1026}, { 1107, 1027},
+{ 1108, 1028}, { 1109, 1029}, { 1110, 1030}, { 1111, 1031}, { 1112, 1032}, { 1113, 1033}, { 1114, 1034},
+{ 1115, 1035}, { 1116, 1036}, { 1117, 1037}, { 1118, 1038}, { 1119, 1039}, { 1121, 1120}, { 1123, 1122}, { 1125, 1124},
+{ 1127, 1126}, { 1129, 1128}, { 1131, 1130}, { 1133, 1132}, { 1135, 1134}, { 1137, 1136}, { 1139, 1138},
+{ 1141, 1140}, { 1143, 1142}, { 1145, 1144}, { 1147, 1146}, { 1149, 1148}, { 1151, 1150}, { 1153, 1152},
+{ 1169, 1168}, { 1171, 1170}, { 1173, 1172}, { 1175, 1174}, { 1177, 1176}, { 1179, 1178}, { 1181, 1180},
+{ 1183, 1182}, { 1185, 1184}, { 1187, 1186}, { 1189, 1188}, { 1191, 1190}, { 1193, 1192}, { 1195, 1194},
+{ 1197, 1196}, { 1199, 1198}, { 1201, 1200}, { 1203, 1202}, { 1205, 1204}, { 1207, 1206}, { 1209, 1208},
+{ 1211, 1210}, { 1213, 1212}, { 1215, 1214}, { 1218, 1217}, { 1220, 1219}, { 1224, 1223}, { 1228, 1227},
+{ 1233, 1232}, { 1235, 1234}, { 1237, 1236}, { 1239, 1238}, { 1241, 1240}, { 1243, 1242}, { 1245, 1244},
+{ 1247, 1246}, { 1249, 1248}, { 1251, 1250}, { 1253, 1252}, { 1255, 1254}, { 1257, 1256}, { 1259, 1258},
+{ 1263, 1262}, { 1265, 1264}, { 1267, 1266}, { 1269, 1268}, { 1273, 1272}, { 1377, 1329}, { 1378, 1330},
+{ 1379, 1331}, { 1380, 1332}, { 1381, 1333}, { 1382, 1334}, { 1383, 1335}, { 1384, 1336}, { 1385, 1337},
+{ 1386, 1338}, { 1387, 1339}, { 1388, 1340}, { 1389, 1341}, { 1390, 1342}, { 1391, 1343}, { 1392, 1344},
+{ 1393, 1345}, { 1394, 1346}, { 1395, 1347}, { 1396, 1348}, { 1397, 1349}, { 1398, 1350}, { 1399, 1351},
+{ 1400, 1352}, { 1401, 1353}, { 1402, 1354}, { 1403, 1355}, { 1404, 1356}, { 1405, 1357}, { 1406, 1358},
+{ 1407, 1359}, { 1408, 1360}, { 1409, 1361}, { 1410, 1362}, { 1411, 1363}, { 1412, 1364}, { 1413, 1365},
+{ 1414, 1366}, { 7681, 7680}, { 7683, 7682}, { 7685, 7684}, { 7687, 7686}, { 7689, 7688}, { 7691, 7690},
+{ 7693, 7692}, { 7695, 7694}, { 7697, 7696}, { 7699, 7698}, { 7701, 7700}, { 7703, 7702}, { 7705, 7704},
+{ 7707, 7706}, { 7709, 7708}, { 7711, 7710}, { 7713, 7712}, { 7715, 7714}, { 7717, 7716}, { 7719, 7718},
+{ 7721, 7720}, { 7723, 7722}, { 7725, 7724}, { 7727, 7726}, { 7729, 7728}, { 7731, 7730}, { 7733, 7732},
+{ 7735, 7734}, { 7737, 7736}, { 7739, 7738}, { 7741, 7740}, { 7743, 7742}, { 7745, 7744}, { 7747, 7746},
+{ 7749, 7748}, { 7751, 7750}, { 7753, 7752}, { 7755, 7754}, { 7757, 7756}, { 7759, 7758}, { 7761, 7760},
+{ 7763, 7762}, { 7765, 7764}, { 7767, 7766}, { 7769, 7768}, { 7771, 7770}, { 7773, 7772}, { 7775, 7774},
+{ 7777, 7776}, { 7779, 7778}, { 7781, 7780}, { 7783, 7782}, { 7785, 7784}, { 7787, 7786}, { 7789, 7788},
+{ 7791, 7790}, { 7793, 7792}, { 7795, 7794}, { 7797, 7796}, { 7799, 7798}, { 7801, 7800}, { 7803, 7802},
+{ 7805, 7804}, { 7807, 7806}, { 7809, 7808}, { 7811, 7810}, { 7813, 7812}, { 7815, 7814}, { 7817, 7816},
+{ 7819, 7818}, { 7821, 7820}, { 7823, 7822}, { 7825, 7824}, { 7827, 7826}, { 7829, 7828}, { 7841, 7840},
+{ 7843, 7842}, { 7845, 7844}, { 7847, 7846}, { 7849, 7848}, { 7851, 7850}, { 7853, 7852}, { 7855, 7854},
+{ 7857, 7856}, { 7859, 7858}, { 7861, 7860}, { 7863, 7862}, { 7865, 7864}, { 7867, 7866}, { 7869, 7868},
+{ 7871, 7870}, { 7873, 7872}, { 7875, 7874}, { 7877, 7876}, { 7879, 7878}, { 7881, 7880}, { 7883, 7882},
+{ 7885, 7884}, { 7887, 7886}, { 7889, 7888}, { 7891, 7890}, { 7893, 7892}, { 7895, 7894}, { 7897, 7896},
+{ 7899, 7898}, { 7901, 7900}, { 7903, 7902}, { 7905, 7904}, { 7907, 7906}, { 7909, 7908}, { 7911, 7910},
+{ 7913, 7912}, { 7915, 7914}, { 7917, 7916}, { 7919, 7918}, { 7921, 7920}, { 7923, 7922}, { 7925, 7924},
+{ 7927, 7926}, { 7929, 7928}, { 7936, 7944}, { 7937, 7945}, { 7938, 7946}, { 7939, 7947}, { 7940, 7948},
+{ 7941, 7949}, { 7942, 7950}, { 7943, 7951}, { 7952, 7960}, { 7953, 7961}, { 7954, 7962}, { 7955, 7963},
+{ 7956, 7964}, { 7957, 7965}, { 7968, 7976}, { 7969, 7977}, { 7970, 7978}, { 7971, 7979}, { 7972, 7980},
+{ 7973, 7981}, { 7974, 7982}, { 7975, 7983}, { 7984, 7992}, { 7985, 7993}, { 7986, 7994}, { 7987, 7995},
+{ 7988, 7996}, { 7989, 7997}, { 7990, 7998}, { 7991, 7999}, { 8000, 8008}, { 8001, 8009}, { 8002, 8010},
+{ 8003, 8011}, { 8004, 8012}, { 8005, 8013}, { 8017, 8025}, { 8019, 8027}, { 8021, 8029}, { 8023, 8031},
+{ 8032, 8040}, { 8033, 8041}, { 8034, 8042}, { 8035, 8043}, { 8036, 8044}, { 8037, 8045}, { 8038, 8046},
+{ 8039, 8047}, { 8048, 8122}, { 8049, 8123}, { 8050, 8136}, { 8051, 8137}, { 8052, 8138}, { 8053, 8139},
+{ 8054, 8154}, { 8055, 8155}, { 8056, 8184}, { 8057, 8185}, { 8058, 8170}, { 8059, 8171}, { 8060, 8186},
+{ 8061, 8187}, { 8112, 8120}, { 8113, 8121}, { 8144, 8152}, { 8145, 8153}, { 8160, 8168}, { 8161, 8169},
+{ 8165, 8172}, { 8560, 8544}, { 8561, 8545}, { 8562, 8546}, { 8563, 8547}, { 8564, 8548}, { 8565, 8549},
+{ 8566, 8550}, { 8567, 8551}, { 8568, 8552}, { 8569, 8553}, { 8570, 8554}, { 8571, 8555}, { 8572, 8556},
+{ 8573, 8557}, { 8574, 8558}, { 8575, 8559}, { 9424, 9398}, { 9425, 9399}, { 9426, 9400}, { 9427, 9401},
+{ 9428, 9402}, { 9429, 9403}, { 9430, 9404}, { 9431, 9405}, { 9432, 9406}, { 9433, 9407}, { 9434, 9408},
+{ 9435, 9409}, { 9436, 9410}, { 9437, 9411}, { 9438, 9412}, { 9439, 9413}, { 9440, 9414}, { 9441, 9415},
+{ 9442, 9416}, { 9443, 9417}, { 9444, 9418}, { 9445, 9419}, { 9446, 9420}, { 9447, 9421}, { 9448, 9422},
+{ 9449, 9423}, {65345,65313}, {65346,65314}, {65347,65315}, {65348,65316}, {65349,65317}, {65350,65318},
+{65351,65319}, {65352,65320}, {65353,65321}, {65354,65322}, {65355,65323}, {65356,65324}, {65357,65325},
+{65358,65326}, {65359,65327}, {65360,65328}, {65361,65329}, {65362,65330}, {65363,65331}, {65364,65332},
+{65365,65333}, {65366,65334}, {65367,65335}, {65368,65336}, {65369,65337}, {65370,65338}, {65535, 0}};
+
+static const GUnicodePairType UnicodeToLowerTable[] = {
+{ 65, 97}, { 66, 98}, { 67, 99}, { 68, 100}, { 69, 101}, { 70, 102}, { 71, 103},
+{ 72, 104}, { 73, 105}, { 74, 106}, { 75, 107}, { 76, 108}, { 77, 109}, { 78, 110},
+{ 79, 111}, { 80, 112}, { 81, 113}, { 82, 114}, { 83, 115}, { 84, 116}, { 85, 117},
+{ 86, 118}, { 87, 119}, { 88, 120}, { 89, 121}, { 90, 122}, { 192, 224}, { 193, 225},
+{ 194, 226}, { 195, 227}, { 196, 228}, { 197, 229}, { 198, 230}, { 199, 231}, { 200, 232},
+{ 201, 233}, { 202, 234}, { 203, 235}, { 204, 236}, { 205, 237}, { 206, 238}, { 207, 239},
+{ 208, 240}, { 209, 241}, { 210, 242}, { 211, 243}, { 212, 244}, { 213, 245}, { 214, 246},
+{ 216, 248}, { 217, 249}, { 218, 250}, { 219, 251}, { 220, 252}, { 221, 253}, { 222, 254},
+{ 256, 257}, { 258, 259}, { 260, 261}, { 262, 263}, { 264, 265}, { 266, 267}, { 268, 269},
+{ 270, 271}, { 272, 273}, { 274, 275}, { 276, 277}, { 278, 279}, { 280, 281}, { 282, 283},
+{ 284, 285}, { 286, 287}, { 288, 289}, { 290, 291}, { 292, 293}, { 294, 295}, { 296, 297},
+{ 298, 299}, { 300, 301}, { 302, 303}, { 304, 105}, { 306, 307}, { 308, 309}, { 310, 311}, { 313, 314},
+{ 315, 316}, { 317, 318}, { 319, 320}, { 321, 322}, { 323, 324}, { 325, 326}, { 327, 328},
+{ 330, 331}, { 332, 333}, { 334, 335}, { 336, 337}, { 338, 339}, { 340, 341}, { 342, 343},
+{ 344, 345}, { 346, 347}, { 348, 349}, { 350, 351}, { 352, 353}, { 354, 355}, { 356, 357},
+{ 358, 359}, { 360, 361}, { 362, 363}, { 364, 365}, { 366, 367}, { 368, 369}, { 370, 371},
+{ 372, 373}, { 374, 375}, { 376, 255}, { 377, 378}, { 379, 380}, { 381, 382}, { 385, 595},
+{ 386, 387}, { 388, 389}, { 390, 596}, { 391, 392}, { 393, 598}, { 394, 599}, { 395, 396},
+{ 398, 477}, { 399, 601}, { 400, 603}, { 401, 402}, { 403, 608}, { 404, 611}, { 406, 617},
+{ 407, 616}, { 408, 409}, { 412, 623}, { 413, 626}, { 415, 629}, { 416, 417}, { 418, 419},
+{ 420, 421}, { 423, 424}, { 425, 643}, { 428, 429}, { 430, 648}, { 431, 432}, { 433, 650},
+{ 434, 651}, { 435, 436}, { 437, 438}, { 439, 658}, { 440, 441}, { 444, 445}, { 452, 454},
+{ 455, 457}, { 458, 460}, { 461, 462}, { 463, 464}, { 465, 466}, { 467, 468}, { 469, 470},
+{ 471, 472}, { 473, 474}, { 475, 476}, { 478, 479}, { 480, 481}, { 482, 483}, { 484, 485},
+{ 486, 487}, { 488, 489}, { 490, 491}, { 492, 493}, { 494, 495}, { 497, 499}, { 500, 501},
+{ 506, 507}, { 508, 509}, { 510, 511}, { 512, 513}, { 514, 515}, { 516, 517}, { 518, 519},
+{ 520, 521}, { 522, 523}, { 524, 525}, { 526, 527}, { 528, 529}, { 530, 531}, { 532, 533},
+{ 534, 535}, { 902, 940}, { 904, 941}, { 905, 942}, { 906, 943}, { 908, 972}, { 910, 973},
+{ 911, 974}, { 913, 945}, { 914, 946}, { 915, 947}, { 916, 948}, { 917, 949}, { 918, 950},
+{ 919, 951}, { 920, 952}, { 921, 953}, { 922, 954}, { 923, 955}, { 924, 956}, { 925, 957},
+{ 926, 958}, { 927, 959}, { 928, 960}, { 929, 961}, { 931, 963}, { 932, 964}, { 933, 965},
+{ 934, 966}, { 935, 967}, { 936, 968}, { 937, 969}, { 938, 970}, { 939, 971}, { 994, 995},
+{ 996, 997}, { 998, 999}, { 1000, 1001}, { 1002, 1003}, { 1004, 1005}, { 1006, 1007}, { 1024, 1104}, { 1025, 1105},
+{ 1026, 1106}, { 1027, 1107}, { 1028, 1108}, { 1029, 1109}, { 1030, 1110}, { 1031, 1111}, { 1032, 1112},
+{ 1033, 1113}, { 1034, 1114}, { 1035, 1115}, { 1036, 1116}, { 1037, 1117}, { 1038, 1118}, { 1039, 1119}, { 1040, 1072},
+{ 1041, 1073}, { 1042, 1074}, { 1043, 1075}, { 1044, 1076}, { 1045, 1077}, { 1046, 1078}, { 1047, 1079},
+{ 1048, 1080}, { 1049, 1081}, { 1050, 1082}, { 1051, 1083}, { 1052, 1084}, { 1053, 1085}, { 1054, 1086},
+{ 1055, 1087}, { 1056, 1088}, { 1057, 1089}, { 1058, 1090}, { 1059, 1091}, { 1060, 1092}, { 1061, 1093},
+{ 1062, 1094}, { 1063, 1095}, { 1064, 1096}, { 1065, 1097}, { 1066, 1098}, { 1067, 1099}, { 1068, 1100},
+{ 1069, 1101}, { 1070, 1102}, { 1071, 1103}, { 1120, 1121}, { 1122, 1123}, { 1124, 1125}, { 1126, 1127},
+{ 1128, 1129}, { 1130, 1131}, { 1132, 1133}, { 1134, 1135}, { 1136, 1137}, { 1138, 1139}, { 1140, 1141},
+{ 1142, 1143}, { 1144, 1145}, { 1146, 1147}, { 1148, 1149}, { 1150, 1151}, { 1152, 1153}, { 1168, 1169},
+{ 1170, 1171}, { 1172, 1173}, { 1174, 1175}, { 1176, 1177}, { 1178, 1179}, { 1180, 1181}, { 1182, 1183},
+{ 1184, 1185}, { 1186, 1187}, { 1188, 1189}, { 1190, 1191}, { 1192, 1193}, { 1194, 1195}, { 1196, 1197},
+{ 1198, 1199}, { 1200, 1201}, { 1202, 1203}, { 1204, 1205}, { 1206, 1207}, { 1208, 1209}, { 1210, 1211},
+{ 1212, 1213}, { 1214, 1215}, { 1217, 1218}, { 1219, 1220}, { 1223, 1224}, { 1227, 1228}, { 1232, 1233},
+{ 1234, 1235}, { 1236, 1237}, { 1238, 1239}, { 1240, 1241}, { 1242, 1243}, { 1244, 1245}, { 1246, 1247},
+{ 1248, 1249}, { 1250, 1251}, { 1252, 1253}, { 1254, 1255}, { 1256, 1257}, { 1258, 1259}, { 1262, 1263},
+{ 1264, 1265}, { 1266, 1267}, { 1268, 1269}, { 1272, 1273}, { 1329, 1377}, { 1330, 1378}, { 1331, 1379},
+{ 1332, 1380}, { 1333, 1381}, { 1334, 1382}, { 1335, 1383}, { 1336, 1384}, { 1337, 1385}, { 1338, 1386},
+{ 1339, 1387}, { 1340, 1388}, { 1341, 1389}, { 1342, 1390}, { 1343, 1391}, { 1344, 1392}, { 1345, 1393},
+{ 1346, 1394}, { 1347, 1395}, { 1348, 1396}, { 1349, 1397}, { 1350, 1398}, { 1351, 1399}, { 1352, 1400},
+{ 1353, 1401}, { 1354, 1402}, { 1355, 1403}, { 1356, 1404}, { 1357, 1405}, { 1358, 1406}, { 1359, 1407},
+{ 1360, 1408}, { 1361, 1409}, { 1362, 1410}, { 1363, 1411}, { 1364, 1412}, { 1365, 1413}, { 1366, 1414},
+{ 4256, 4304}, { 4257, 4305}, { 4258, 4306}, { 4259, 4307}, { 4260, 4308}, { 4261, 4309}, { 4262, 4310},
+{ 4263, 4311}, { 4264, 4312}, { 4265, 4313}, { 4266, 4314}, { 4267, 4315}, { 4268, 4316}, { 4269, 4317},
+{ 4270, 4318}, { 4271, 4319}, { 4272, 4320}, { 4273, 4321}, { 4274, 4322}, { 4275, 4323}, { 4276, 4324},
+{ 4277, 4325}, { 4278, 4326}, { 4279, 4327}, { 4280, 4328}, { 4281, 4329}, { 4282, 4330}, { 4283, 4331},
+{ 4284, 4332}, { 4285, 4333}, { 4286, 4334}, { 4287, 4335}, { 4288, 4336}, { 4289, 4337}, { 4290, 4338},
+{ 4291, 4339}, { 4292, 4340}, { 4293, 4341}, { 7680, 7681}, { 7682, 7683}, { 7684, 7685}, { 7686, 7687},
+{ 7688, 7689}, { 7690, 7691}, { 7692, 7693}, { 7694, 7695}, { 7696, 7697}, { 7698, 7699}, { 7700, 7701},
+{ 7702, 7703}, { 7704, 7705}, { 7706, 7707}, { 7708, 7709}, { 7710, 7711}, { 7712, 7713}, { 7714, 7715},
+{ 7716, 7717}, { 7718, 7719}, { 7720, 7721}, { 7722, 7723}, { 7724, 7725}, { 7726, 7727}, { 7728, 7729},
+{ 7730, 7731}, { 7732, 7733}, { 7734, 7735}, { 7736, 7737}, { 7738, 7739}, { 7740, 7741}, { 7742, 7743},
+{ 7744, 7745}, { 7746, 7747}, { 7748, 7749}, { 7750, 7751}, { 7752, 7753}, { 7754, 7755}, { 7756, 7757},
+{ 7758, 7759}, { 7760, 7761}, { 7762, 7763}, { 7764, 7765}, { 7766, 7767}, { 7768, 7769}, { 7770, 7771},
+{ 7772, 7773}, { 7774, 7775}, { 7776, 7777}, { 7778, 7779}, { 7780, 7781}, { 7782, 7783}, { 7784, 7785},
+{ 7786, 7787}, { 7788, 7789}, { 7790, 7791}, { 7792, 7793}, { 7794, 7795}, { 7796, 7797}, { 7798, 7799},
+{ 7800, 7801}, { 7802, 7803}, { 7804, 7805}, { 7806, 7807}, { 7808, 7809}, { 7810, 7811}, { 7812, 7813},
+{ 7814, 7815}, { 7816, 7817}, { 7818, 7819}, { 7820, 7821}, { 7822, 7823}, { 7824, 7825}, { 7826, 7827},
+{ 7828, 7829}, { 7840, 7841}, { 7842, 7843}, { 7844, 7845}, { 7846, 7847}, { 7848, 7849}, { 7850, 7851},
+{ 7852, 7853}, { 7854, 7855}, { 7856, 7857}, { 7858, 7859}, { 7860, 7861}, { 7862, 7863}, { 7864, 7865},
+{ 7866, 7867}, { 7868, 7869}, { 7870, 7871}, { 7872, 7873}, { 7874, 7875}, { 7876, 7877}, { 7878, 7879},
+{ 7880, 7881}, { 7882, 7883}, { 7884, 7885}, { 7886, 7887}, { 7888, 7889}, { 7890, 7891}, { 7892, 7893},
+{ 7894, 7895}, { 7896, 7897}, { 7898, 7899}, { 7900, 7901}, { 7902, 7903}, { 7904, 7905}, { 7906, 7907},
+{ 7908, 7909}, { 7910, 7911}, { 7912, 7913}, { 7914, 7915}, { 7916, 7917}, { 7918, 7919}, { 7920, 7921},
+{ 7922, 7923}, { 7924, 7925}, { 7926, 7927}, { 7928, 7929}, { 7944, 7936}, { 7945, 7937}, { 7946, 7938},
+{ 7947, 7939}, { 7948, 7940}, { 7949, 7941}, { 7950, 7942}, { 7951, 7943}, { 7960, 7952}, { 7961, 7953},
+{ 7962, 7954}, { 7963, 7955}, { 7964, 7956}, { 7965, 7957}, { 7976, 7968}, { 7977, 7969}, { 7978, 7970},
+{ 7979, 7971}, { 7980, 7972}, { 7981, 7973}, { 7982, 7974}, { 7983, 7975}, { 7992, 7984}, { 7993, 7985},
+{ 7994, 7986}, { 7995, 7987}, { 7996, 7988}, { 7997, 7989}, { 7998, 7990}, { 7999, 7991}, { 8008, 8000},
+{ 8009, 8001}, { 8010, 8002}, { 8011, 8003}, { 8012, 8004}, { 8013, 8005}, { 8025, 8017}, { 8027, 8019},
+{ 8029, 8021}, { 8031, 8023}, { 8040, 8032}, { 8041, 8033}, { 8042, 8034}, { 8043, 8035}, { 8044, 8036},
+{ 8045, 8037}, { 8046, 8038}, { 8047, 8039}, { 8120, 8112}, { 8121, 8113}, { 8122, 8048}, { 8123, 8049},
+{ 8136, 8050}, { 8137, 8051}, { 8138, 8052}, { 8139, 8053}, { 8152, 8144}, { 8153, 8145}, { 8154, 8054},
+{ 8155, 8055}, { 8168, 8160}, { 8169, 8161}, { 8170, 8058}, { 8171, 8059}, { 8172, 8165}, { 8184, 8056},
+{ 8185, 8057}, { 8186, 8060}, { 8187, 8061}, { 8544, 8560}, { 8545, 8561}, { 8546, 8562}, { 8547, 8563},
+{ 8548, 8564}, { 8549, 8565}, { 8550, 8566}, { 8551, 8567}, { 8552, 8568}, { 8553, 8569}, { 8554, 8570},
+{ 8555, 8571}, { 8556, 8572}, { 8557, 8573}, { 8558, 8574}, { 8559, 8575}, { 9398, 9424}, { 9399, 9425},
+{ 9400, 9426}, { 9401, 9427}, { 9402, 9428}, { 9403, 9429}, { 9404, 9430}, { 9405, 9431}, { 9406, 9432},
+{ 9407, 9433}, { 9408, 9434}, { 9409, 9435}, { 9410, 9436}, { 9411, 9437}, { 9412, 9438}, { 9413, 9439},
+{ 9414, 9440}, { 9415, 9441}, { 9416, 9442}, { 9417, 9443}, { 9418, 9444}, { 9419, 9445}, { 9420, 9446},
+{ 9421, 9447}, { 9422, 9448}, { 9423, 9449}, {65313,65345}, {65314,65346}, {65315,65347}, {65316,65348},
+{65317,65349}, {65318,65350}, {65319,65351}, {65320,65352}, {65321,65353}, {65322,65354}, {65323,65355},
+{65324,65356}, {65325,65357}, {65326,65358}, {65327,65359}, {65328,65360}, {65329,65361}, {65330,65362},
+{65331,65363}, {65332,65364}, {65333,65365}, {65334,65366}, {65335,65367}, {65336,65368}, {65337,65369},
+{65338,65370}, {65535, 0}};
+
+int OVR_CDECL OVR_towupper(wchar_t charCode)
+{
+ // Don't use UnicodeUpperBits! It differs from UnicodeToUpperBits.
+ if (UnicodeCharIs(UnicodeToUpperBits, charCode))
+ {
+ // To protect from memory overrun in case the character is not found
+ // we use one extra fake element in the table {65536, 0}.
+ UPInt idx = Alg::LowerBoundSliced(
+ UnicodeToUpperTable,
+ 0,
+ sizeof(UnicodeToUpperTable) / sizeof(UnicodeToUpperTable[0]) - 1,
+ (UInt16)charCode,
+ CmpUnicodeKey);
+ return UnicodeToUpperTable[idx].Value;
+ }
+ return charCode;
+}
+
+int OVR_CDECL OVR_towlower(wchar_t charCode)
+{
+ // Don't use UnicodeLowerBits! It differs from UnicodeToLowerBits.
+ if (UnicodeCharIs(UnicodeToLowerBits, charCode))
+ {
+ // To protect from memory overrun in case the character is not found
+ // we use one extra fake element in the table {65536, 0}.
+ UPInt idx = Alg::LowerBoundSliced(
+ UnicodeToLowerTable,
+ 0,
+ sizeof(UnicodeToLowerTable) / sizeof(UnicodeToLowerTable[0]) - 1,
+ (UInt16)charCode,
+ CmpUnicodeKey);
+ return UnicodeToLowerTable[idx].Value;
+ }
+ return charCode;
+}
+
+#endif //OVR_NO_WCTYPE
+
+} // OVR
diff --git a/LibOVR/Src/Kernel/OVR_Std.h b/LibOVR/Src/Kernel/OVR_Std.h
index b20a376..f8d8a3c 100644
--- a/LibOVR/Src/Kernel/OVR_Std.h
+++ b/LibOVR/Src/Kernel/OVR_Std.h
@@ -1,503 +1,503 @@
-/************************************************************************************
-
-PublicHeader: OVR.h
-Filename : OVR_Std.h
-Content : Standard C function interface
-Created : September 19, 2012
-Notes :
-
-Copyright : Copyright 2012 Oculus VR, Inc. All Rights reserved.
-
-Use of this software is subject to the terms of the Oculus license
-agreement provided at the time of installation or download, or which
-otherwise accompanies this software in either electronic or hard copy form.
-
-************************************************************************************/
-
-#ifndef OVR_Std_h
-#define OVR_Std_h
-
-#include "OVR_Types.h"
-#include <stdarg.h> // for va_list args
-#include <string.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <ctype.h>
-
-#if !defined(OVR_OS_WINCE) && defined(OVR_CC_MSVC) && (OVR_CC_MSVC >= 1400)
-#define OVR_MSVC_SAFESTRING
-#include <errno.h>
-#endif
-
-// Wide-char funcs
-#include <wchar.h>
-#include <wctype.h>
-
-namespace OVR {
-
-#if defined(OVR_OS_WIN32)
-inline char* OVR_CDECL OVR_itoa(int val, char *dest, UPInt destsize, int radix)
-{
-#if defined(OVR_MSVC_SAFESTRING)
- _itoa_s(val, dest, destsize, radix);
- return dest;
-#else
- OVR_UNUSED(destsize);
- return itoa(val, dest, radix);
-#endif
-}
-#else // OVR_OS_WIN32
-inline char* OVR_itoa(int val, char* dest, unsigned int len, int radix)
-{
- if (val == 0)
- {
- if (len > 1)
- {
- dest[0] = '0';
- dest[1] = '\0';
- }
- return dest;
- }
-
- int cur = val;
- unsigned int i = 0;
- unsigned int sign = 0;
-
- if (val < 0)
- {
- val = -val;
- sign = 1;
- }
-
- while ((val != 0) && (i < (len - 1 - sign)))
- {
- cur = val % radix;
- val /= radix;
-
- if (radix == 16)
- {
- switch(cur)
- {
- case 10:
- dest[i] = 'a';
- break;
- case 11:
- dest[i] = 'b';
- break;
- case 12:
- dest[i] = 'c';
- break;
- case 13:
- dest[i] = 'd';
- break;
- case 14:
- dest[i] = 'e';
- break;
- case 15:
- dest[i] = 'f';
- break;
- default:
- dest[i] = (char)('0' + cur);
- break;
- }
- }
- else
- {
- dest[i] = (char)('0' + cur);
- }
- ++i;
- }
-
- if (sign)
- {
- dest[i++] = '-';
- }
-
- for (unsigned int j = 0; j < i / 2; ++j)
- {
- char tmp = dest[j];
- dest[j] = dest[i - 1 - j];
- dest[i - 1 - j] = tmp;
- }
- dest[i] = '\0';
-
- return dest;
-}
-
-#endif
-
-
-// String functions
-
-inline UPInt OVR_CDECL OVR_strlen(const char* str)
-{
- return strlen(str);
-}
-
-inline char* OVR_CDECL OVR_strcpy(char* dest, UPInt destsize, const char* src)
-{
-#if defined(OVR_MSVC_SAFESTRING)
- strcpy_s(dest, destsize, src);
- return dest;
-#else
- OVR_UNUSED(destsize);
- return strcpy(dest, src);
-#endif
-}
-
-inline char* OVR_CDECL OVR_strncpy(char* dest, UPInt destsize, const char* src, UPInt count)
-{
-#if defined(OVR_MSVC_SAFESTRING)
- strncpy_s(dest, destsize, src, count);
- return dest;
-#else
- OVR_UNUSED(destsize);
- return strncpy(dest, src, count);
-#endif
-}
-
-inline char * OVR_CDECL OVR_strcat(char* dest, UPInt destsize, const char* src)
-{
-#if defined(OVR_MSVC_SAFESTRING)
- strcat_s(dest, destsize, src);
- return dest;
-#else
- OVR_UNUSED(destsize);
- return strcat(dest, src);
-#endif
-}
-
-inline int OVR_CDECL OVR_strcmp(const char* dest, const char* src)
-{
- return strcmp(dest, src);
-}
-
-inline const char* OVR_CDECL OVR_strchr(const char* str, char c)
-{
- return strchr(str, c);
-}
-
-inline char* OVR_CDECL OVR_strchr(char* str, char c)
-{
- return strchr(str, c);
-}
-
-inline const char* OVR_strrchr(const char* str, char c)
-{
- UPInt len = OVR_strlen(str);
- for (UPInt i=len; i>0; i--)
- if (str[i]==c)
- return str+i;
- return 0;
-}
-
-inline const UByte* OVR_CDECL OVR_memrchr(const UByte* str, UPInt size, UByte c)
-{
- for (SPInt i = (SPInt)size - 1; i >= 0; i--)
- {
- if (str[i] == c)
- return str + i;
- }
- return 0;
-}
-
-inline char* OVR_CDECL OVR_strrchr(char* str, char c)
-{
- UPInt len = OVR_strlen(str);
- for (UPInt i=len; i>0; i--)
- if (str[i]==c)
- return str+i;
- return 0;
-}
-
-
-double OVR_CDECL OVR_strtod(const char* string, char** tailptr);
-
-inline long OVR_CDECL OVR_strtol(const char* string, char** tailptr, int radix)
-{
- return strtol(string, tailptr, radix);
-}
-
-inline long OVR_CDECL OVR_strtoul(const char* string, char** tailptr, int radix)
-{
- return strtoul(string, tailptr, radix);
-}
-
-inline int OVR_CDECL OVR_strncmp(const char* ws1, const char* ws2, UPInt size)
-{
- return strncmp(ws1, ws2, size);
-}
-
-inline UInt64 OVR_CDECL OVR_strtouq(const char *nptr, char **endptr, int base)
-{
-#if defined(OVR_CC_MSVC) && !defined(OVR_OS_WINCE)
- return _strtoui64(nptr, endptr, base);
-#else
- return strtoull(nptr, endptr, base);
-#endif
-}
-
-inline SInt64 OVR_CDECL OVR_strtoq(const char *nptr, char **endptr, int base)
-{
-#if defined(OVR_CC_MSVC) && !defined(OVR_OS_WINCE)
- return _strtoi64(nptr, endptr, base);
-#else
- return strtoll(nptr, endptr, base);
-#endif
-}
-
-
-inline SInt64 OVR_CDECL OVR_atoq(const char* string)
-{
-#if defined(OVR_CC_MSVC) && !defined(OVR_OS_WINCE)
- return _atoi64(string);
-#else
- return atoll(string);
-#endif
-}
-
-inline UInt64 OVR_CDECL OVR_atouq(const char* string)
-{
- return OVR_strtouq(string, NULL, 10);
-}
-
-
-// Implemented in GStd.cpp in platform-specific manner.
-int OVR_CDECL OVR_stricmp(const char* dest, const char* src);
-int OVR_CDECL OVR_strnicmp(const char* dest, const char* src, UPInt count);
-
-inline UPInt OVR_CDECL OVR_sprintf(char *dest, UPInt destsize, const char* format, ...)
-{
- va_list argList;
- va_start(argList,format);
- UPInt ret;
-#if defined(OVR_CC_MSVC)
- #if defined(OVR_MSVC_SAFESTRING)
- ret = _vsnprintf_s(dest, destsize, _TRUNCATE, format, argList);
- OVR_ASSERT(ret != -1);
- #else
- OVR_UNUSED(destsize);
- ret = _vsnprintf(dest, destsize - 1, format, argList); // -1 for space for the null character
- OVR_ASSERT(ret != -1);
- dest[destsize-1] = 0;
- #endif
-#else
- OVR_UNUSED(destsize);
- ret = vsprintf(dest, format, argList);
- OVR_ASSERT(ret < destsize);
-#endif
- va_end(argList);
- return ret;
-}
-
-inline UPInt OVR_CDECL OVR_vsprintf(char *dest, UPInt destsize, const char * format, va_list argList)
-{
- UPInt ret;
-#if defined(OVR_CC_MSVC)
- #if defined(OVR_MSVC_SAFESTRING)
- dest[0] = '\0';
- int rv = vsnprintf_s(dest, destsize, _TRUNCATE, format, argList);
- if (rv == -1)
- {
- dest[destsize - 1] = '\0';
- ret = destsize - 1;
- }
- else
- ret = (UPInt)rv;
- #else
- OVR_UNUSED(destsize);
- int rv = _vsnprintf(dest, destsize - 1, format, argList);
- OVR_ASSERT(rv != -1);
- ret = (UPInt)rv;
- dest[destsize-1] = 0;
- #endif
-#else
- OVR_UNUSED(destsize);
- ret = (UPInt)vsprintf(dest, format, argList);
- OVR_ASSERT(ret < destsize);
-#endif
- return ret;
-}
-
-// Returns the number of characters in the formatted string.
-inline UPInt OVR_CDECL OVR_vscprintf(const char * format, va_list argList)
-{
- UPInt ret;
-#if defined(OVR_CC_MSVC)
- ret = (UPInt) _vscprintf(format, argList);
-#else
- ret = (UPInt) vsnprintf(NULL, 0, format, argList);
-#endif
- return ret;
-}
-
-
-wchar_t* OVR_CDECL OVR_wcscpy(wchar_t* dest, UPInt destsize, const wchar_t* src);
-wchar_t* OVR_CDECL OVR_wcsncpy(wchar_t* dest, UPInt destsize, const wchar_t* src, UPInt count);
-wchar_t* OVR_CDECL OVR_wcscat(wchar_t* dest, UPInt destsize, const wchar_t* src);
-UPInt OVR_CDECL OVR_wcslen(const wchar_t* str);
-int OVR_CDECL OVR_wcscmp(const wchar_t* a, const wchar_t* b);
-int OVR_CDECL OVR_wcsicmp(const wchar_t* a, const wchar_t* b);
-
-inline int OVR_CDECL OVR_wcsicoll(const wchar_t* a, const wchar_t* b)
-{
-#if defined(OVR_OS_WIN32)
-#if defined(OVR_CC_MSVC) && (OVR_CC_MSVC >= 1400)
- return ::_wcsicoll(a, b);
-#else
- return ::wcsicoll(a, b);
-#endif
-#else
- // not supported, use regular wcsicmp
- return OVR_wcsicmp(a, b);
-#endif
-}
-
-inline int OVR_CDECL OVR_wcscoll(const wchar_t* a, const wchar_t* b)
-{
-#if defined(OVR_OS_WIN32) || defined(OVR_OS_LINUX)
- return wcscoll(a, b);
-#else
- // not supported, use regular wcscmp
- return OVR_wcscmp(a, b);
-#endif
-}
-
-#ifndef OVR_NO_WCTYPE
-
-inline int OVR_CDECL UnicodeCharIs(const UInt16* table, wchar_t charCode)
-{
- unsigned offset = table[charCode >> 8];
- if (offset == 0) return 0;
- if (offset == 1) return 1;
- return (table[offset + ((charCode >> 4) & 15)] & (1 << (charCode & 15))) != 0;
-}
-
-extern const UInt16 UnicodeAlnumBits[];
-extern const UInt16 UnicodeAlphaBits[];
-extern const UInt16 UnicodeDigitBits[];
-extern const UInt16 UnicodeSpaceBits[];
-extern const UInt16 UnicodeXDigitBits[];
-
-// Uncomment if necessary
-//extern const UInt16 UnicodeCntrlBits[];
-//extern const UInt16 UnicodeGraphBits[];
-//extern const UInt16 UnicodeLowerBits[];
-//extern const UInt16 UnicodePrintBits[];
-//extern const UInt16 UnicodePunctBits[];
-//extern const UInt16 UnicodeUpperBits[];
-
-inline int OVR_CDECL OVR_iswalnum (wchar_t charCode) { return UnicodeCharIs(UnicodeAlnumBits, charCode); }
-inline int OVR_CDECL OVR_iswalpha (wchar_t charCode) { return UnicodeCharIs(UnicodeAlphaBits, charCode); }
-inline int OVR_CDECL OVR_iswdigit (wchar_t charCode) { return UnicodeCharIs(UnicodeDigitBits, charCode); }
-inline int OVR_CDECL OVR_iswspace (wchar_t charCode) { return UnicodeCharIs(UnicodeSpaceBits, charCode); }
-inline int OVR_CDECL OVR_iswxdigit(wchar_t charCode) { return UnicodeCharIs(UnicodeXDigitBits, charCode); }
-
-// Uncomment if necessary
-//inline int OVR_CDECL OVR_iswcntrl (wchar_t charCode) { return UnicodeCharIs(UnicodeCntrlBits, charCode); }
-//inline int OVR_CDECL OVR_iswgraph (wchar_t charCode) { return UnicodeCharIs(UnicodeGraphBits, charCode); }
-//inline int OVR_CDECL OVR_iswlower (wchar_t charCode) { return UnicodeCharIs(UnicodeLowerBits, charCode); }
-//inline int OVR_CDECL OVR_iswprint (wchar_t charCode) { return UnicodeCharIs(UnicodePrintBits, charCode); }
-//inline int OVR_CDECL OVR_iswpunct (wchar_t charCode) { return UnicodeCharIs(UnicodePunctBits, charCode); }
-//inline int OVR_CDECL OVR_iswupper (wchar_t charCode) { return UnicodeCharIs(UnicodeUpperBits, charCode); }
-
-int OVR_CDECL OVR_towupper(wchar_t charCode);
-int OVR_CDECL OVR_towlower(wchar_t charCode);
-
-#else // OVR_NO_WCTYPE
-
-inline int OVR_CDECL OVR_iswspace(wchar_t c)
-{
- return iswspace(c);
-}
-
-inline int OVR_CDECL OVR_iswdigit(wchar_t c)
-{
- return iswdigit(c);
-}
-
-inline int OVR_CDECL OVR_iswxdigit(wchar_t c)
-{
- return iswxdigit(c);
-}
-
-inline int OVR_CDECL OVR_iswalpha(wchar_t c)
-{
- return iswalpha(c);
-}
-
-inline int OVR_CDECL OVR_iswalnum(wchar_t c)
-{
- return iswalnum(c);
-}
-
-inline wchar_t OVR_CDECL OVR_towlower(wchar_t c)
-{
- return (wchar_t)towlower(c);
-}
-
-inline wchar_t OVR_towupper(wchar_t c)
-{
- return (wchar_t)towupper(c);
-}
-
-#endif // OVR_NO_WCTYPE
-
-// ASCII versions of tolower and toupper. Don't use "char"
-inline int OVR_CDECL OVR_tolower(int c)
-{
- return (c >= 'A' && c <= 'Z') ? c - 'A' + 'a' : c;
-}
-
-inline int OVR_CDECL OVR_toupper(int c)
-{
- return (c >= 'a' && c <= 'z') ? c - 'a' + 'A' : c;
-}
-
-
-
-inline double OVR_CDECL OVR_wcstod(const wchar_t* string, wchar_t** tailptr)
-{
-#if defined(OVR_OS_OTHER)
- OVR_UNUSED(tailptr);
- char buffer[64];
- char* tp = NULL;
- UPInt max = OVR_wcslen(string);
- if (max > 63) max = 63;
- unsigned char c = 0;
- for (UPInt i=0; i < max; i++)
- {
- c = (unsigned char)string[i];
- buffer[i] = ((c) < 128 ? (char)c : '!');
- }
- buffer[max] = 0;
- return OVR_strtod(buffer, &tp);
-#else
- return wcstod(string, tailptr);
-#endif
-}
-
-inline long OVR_CDECL OVR_wcstol(const wchar_t* string, wchar_t** tailptr, int radix)
-{
-#if defined(OVR_OS_OTHER)
- OVR_UNUSED(tailptr);
- char buffer[64];
- char* tp = NULL;
- UPInt max = OVR_wcslen(string);
- if (max > 63) max = 63;
- unsigned char c = 0;
- for (UPInt i=0; i < max; i++)
- {
- c = (unsigned char)string[i];
- buffer[i] = ((c) < 128 ? (char)c : '!');
- }
- buffer[max] = 0;
- return strtol(buffer, &tp, radix);
-#else
- return wcstol(string, tailptr, radix);
-#endif
-}
-
-} // OVR
-
-#endif // OVR_Std_h
+/************************************************************************************
+
+PublicHeader: OVR.h
+Filename : OVR_Std.h
+Content : Standard C function interface
+Created : September 19, 2012
+Notes :
+
+Copyright : Copyright 2012 Oculus VR, Inc. All Rights reserved.
+
+Use of this software is subject to the terms of the Oculus license
+agreement provided at the time of installation or download, or which
+otherwise accompanies this software in either electronic or hard copy form.
+
+************************************************************************************/
+
+#ifndef OVR_Std_h
+#define OVR_Std_h
+
+#include "OVR_Types.h"
+#include <stdarg.h> // for va_list args
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+
+#if !defined(OVR_OS_WINCE) && defined(OVR_CC_MSVC) && (OVR_CC_MSVC >= 1400)
+#define OVR_MSVC_SAFESTRING
+#include <errno.h>
+#endif
+
+// Wide-char funcs
+#include <wchar.h>
+#include <wctype.h>
+
+namespace OVR {
+
+#if defined(OVR_OS_WIN32)
+inline char* OVR_CDECL OVR_itoa(int val, char *dest, UPInt destsize, int radix)
+{
+#if defined(OVR_MSVC_SAFESTRING)
+ _itoa_s(val, dest, destsize, radix);
+ return dest;
+#else
+ OVR_UNUSED(destsize);
+ return itoa(val, dest, radix);
+#endif
+}
+#else // OVR_OS_WIN32
+inline char* OVR_itoa(int val, char* dest, unsigned int len, int radix)
+{
+ if (val == 0)
+ {
+ if (len > 1)
+ {
+ dest[0] = '0';
+ dest[1] = '\0';
+ }
+ return dest;
+ }
+
+ int cur = val;
+ unsigned int i = 0;
+ unsigned int sign = 0;
+
+ if (val < 0)
+ {
+ val = -val;
+ sign = 1;
+ }
+
+ while ((val != 0) && (i < (len - 1 - sign)))
+ {
+ cur = val % radix;
+ val /= radix;
+
+ if (radix == 16)
+ {
+ switch(cur)
+ {
+ case 10:
+ dest[i] = 'a';
+ break;
+ case 11:
+ dest[i] = 'b';
+ break;
+ case 12:
+ dest[i] = 'c';
+ break;
+ case 13:
+ dest[i] = 'd';
+ break;
+ case 14:
+ dest[i] = 'e';
+ break;
+ case 15:
+ dest[i] = 'f';
+ break;
+ default:
+ dest[i] = (char)('0' + cur);
+ break;
+ }
+ }
+ else
+ {
+ dest[i] = (char)('0' + cur);
+ }
+ ++i;
+ }
+
+ if (sign)
+ {
+ dest[i++] = '-';
+ }
+
+ for (unsigned int j = 0; j < i / 2; ++j)
+ {
+ char tmp = dest[j];
+ dest[j] = dest[i - 1 - j];
+ dest[i - 1 - j] = tmp;
+ }
+ dest[i] = '\0';
+
+ return dest;
+}
+
+#endif
+
+
+// String functions
+
+inline UPInt OVR_CDECL OVR_strlen(const char* str)
+{
+ return strlen(str);
+}
+
+inline char* OVR_CDECL OVR_strcpy(char* dest, UPInt destsize, const char* src)
+{
+#if defined(OVR_MSVC_SAFESTRING)
+ strcpy_s(dest, destsize, src);
+ return dest;
+#else
+ OVR_UNUSED(destsize);
+ return strcpy(dest, src);
+#endif
+}
+
+inline char* OVR_CDECL OVR_strncpy(char* dest, UPInt destsize, const char* src, UPInt count)
+{
+#if defined(OVR_MSVC_SAFESTRING)
+ strncpy_s(dest, destsize, src, count);
+ return dest;
+#else
+ OVR_UNUSED(destsize);
+ return strncpy(dest, src, count);
+#endif
+}
+
+inline char * OVR_CDECL OVR_strcat(char* dest, UPInt destsize, const char* src)
+{
+#if defined(OVR_MSVC_SAFESTRING)
+ strcat_s(dest, destsize, src);
+ return dest;
+#else
+ OVR_UNUSED(destsize);
+ return strcat(dest, src);
+#endif
+}
+
+inline int OVR_CDECL OVR_strcmp(const char* dest, const char* src)
+{
+ return strcmp(dest, src);
+}
+
+inline const char* OVR_CDECL OVR_strchr(const char* str, char c)
+{
+ return strchr(str, c);
+}
+
+inline char* OVR_CDECL OVR_strchr(char* str, char c)
+{
+ return strchr(str, c);
+}
+
+inline const char* OVR_strrchr(const char* str, char c)
+{
+ UPInt len = OVR_strlen(str);
+ for (UPInt i=len; i>0; i--)
+ if (str[i]==c)
+ return str+i;
+ return 0;
+}
+
+inline const UByte* OVR_CDECL OVR_memrchr(const UByte* str, UPInt size, UByte c)
+{
+ for (SPInt i = (SPInt)size - 1; i >= 0; i--)
+ {
+ if (str[i] == c)
+ return str + i;
+ }
+ return 0;
+}
+
+inline char* OVR_CDECL OVR_strrchr(char* str, char c)
+{
+ UPInt len = OVR_strlen(str);
+ for (UPInt i=len; i>0; i--)
+ if (str[i]==c)
+ return str+i;
+ return 0;
+}
+
+
+double OVR_CDECL OVR_strtod(const char* string, char** tailptr);
+
+inline long OVR_CDECL OVR_strtol(const char* string, char** tailptr, int radix)
+{
+ return strtol(string, tailptr, radix);
+}
+
+inline long OVR_CDECL OVR_strtoul(const char* string, char** tailptr, int radix)
+{
+ return strtoul(string, tailptr, radix);
+}
+
+inline int OVR_CDECL OVR_strncmp(const char* ws1, const char* ws2, UPInt size)
+{
+ return strncmp(ws1, ws2, size);
+}
+
+inline UInt64 OVR_CDECL OVR_strtouq(const char *nptr, char **endptr, int base)
+{
+#if defined(OVR_CC_MSVC) && !defined(OVR_OS_WINCE)
+ return _strtoui64(nptr, endptr, base);
+#else
+ return strtoull(nptr, endptr, base);
+#endif
+}
+
+inline SInt64 OVR_CDECL OVR_strtoq(const char *nptr, char **endptr, int base)
+{
+#if defined(OVR_CC_MSVC) && !defined(OVR_OS_WINCE)
+ return _strtoi64(nptr, endptr, base);
+#else
+ return strtoll(nptr, endptr, base);
+#endif
+}
+
+
+inline SInt64 OVR_CDECL OVR_atoq(const char* string)
+{
+#if defined(OVR_CC_MSVC) && !defined(OVR_OS_WINCE)
+ return _atoi64(string);
+#else
+ return atoll(string);
+#endif
+}
+
+inline UInt64 OVR_CDECL OVR_atouq(const char* string)
+{
+ return OVR_strtouq(string, NULL, 10);
+}
+
+
+// Implemented in GStd.cpp in platform-specific manner.
+int OVR_CDECL OVR_stricmp(const char* dest, const char* src);
+int OVR_CDECL OVR_strnicmp(const char* dest, const char* src, UPInt count);
+
+inline UPInt OVR_CDECL OVR_sprintf(char *dest, UPInt destsize, const char* format, ...)
+{
+ va_list argList;
+ va_start(argList,format);
+ UPInt ret;
+#if defined(OVR_CC_MSVC)
+ #if defined(OVR_MSVC_SAFESTRING)
+ ret = _vsnprintf_s(dest, destsize, _TRUNCATE, format, argList);
+ OVR_ASSERT(ret != -1);
+ #else
+ OVR_UNUSED(destsize);
+ ret = _vsnprintf(dest, destsize - 1, format, argList); // -1 for space for the null character
+ OVR_ASSERT(ret != -1);
+ dest[destsize-1] = 0;
+ #endif
+#else
+ OVR_UNUSED(destsize);
+ ret = vsprintf(dest, format, argList);
+ OVR_ASSERT(ret < destsize);
+#endif
+ va_end(argList);
+ return ret;
+}
+
+inline UPInt OVR_CDECL OVR_vsprintf(char *dest, UPInt destsize, const char * format, va_list argList)
+{
+ UPInt ret;
+#if defined(OVR_CC_MSVC)
+ #if defined(OVR_MSVC_SAFESTRING)
+ dest[0] = '\0';
+ int rv = vsnprintf_s(dest, destsize, _TRUNCATE, format, argList);
+ if (rv == -1)
+ {
+ dest[destsize - 1] = '\0';
+ ret = destsize - 1;
+ }
+ else
+ ret = (UPInt)rv;
+ #else
+ OVR_UNUSED(destsize);
+ int rv = _vsnprintf(dest, destsize - 1, format, argList);
+ OVR_ASSERT(rv != -1);
+ ret = (UPInt)rv;
+ dest[destsize-1] = 0;
+ #endif
+#else
+ OVR_UNUSED(destsize);
+ ret = (UPInt)vsprintf(dest, format, argList);
+ OVR_ASSERT(ret < destsize);
+#endif
+ return ret;
+}
+
+// Returns the number of characters in the formatted string.
+inline UPInt OVR_CDECL OVR_vscprintf(const char * format, va_list argList)
+{
+ UPInt ret;
+#if defined(OVR_CC_MSVC)
+ ret = (UPInt) _vscprintf(format, argList);
+#else
+ ret = (UPInt) vsnprintf(NULL, 0, format, argList);
+#endif
+ return ret;
+}
+
+
+wchar_t* OVR_CDECL OVR_wcscpy(wchar_t* dest, UPInt destsize, const wchar_t* src);
+wchar_t* OVR_CDECL OVR_wcsncpy(wchar_t* dest, UPInt destsize, const wchar_t* src, UPInt count);
+wchar_t* OVR_CDECL OVR_wcscat(wchar_t* dest, UPInt destsize, const wchar_t* src);
+UPInt OVR_CDECL OVR_wcslen(const wchar_t* str);
+int OVR_CDECL OVR_wcscmp(const wchar_t* a, const wchar_t* b);
+int OVR_CDECL OVR_wcsicmp(const wchar_t* a, const wchar_t* b);
+
+inline int OVR_CDECL OVR_wcsicoll(const wchar_t* a, const wchar_t* b)
+{
+#if defined(OVR_OS_WIN32)
+#if defined(OVR_CC_MSVC) && (OVR_CC_MSVC >= 1400)
+ return ::_wcsicoll(a, b);
+#else
+ return ::wcsicoll(a, b);
+#endif
+#else
+ // not supported, use regular wcsicmp
+ return OVR_wcsicmp(a, b);
+#endif
+}
+
+inline int OVR_CDECL OVR_wcscoll(const wchar_t* a, const wchar_t* b)
+{
+#if defined(OVR_OS_WIN32) || defined(OVR_OS_LINUX)
+ return wcscoll(a, b);
+#else
+ // not supported, use regular wcscmp
+ return OVR_wcscmp(a, b);
+#endif
+}
+
+#ifndef OVR_NO_WCTYPE
+
+inline int OVR_CDECL UnicodeCharIs(const UInt16* table, wchar_t charCode)
+{
+ unsigned offset = table[charCode >> 8];
+ if (offset == 0) return 0;
+ if (offset == 1) return 1;
+ return (table[offset + ((charCode >> 4) & 15)] & (1 << (charCode & 15))) != 0;
+}
+
+extern const UInt16 UnicodeAlnumBits[];
+extern const UInt16 UnicodeAlphaBits[];
+extern const UInt16 UnicodeDigitBits[];
+extern const UInt16 UnicodeSpaceBits[];
+extern const UInt16 UnicodeXDigitBits[];
+
+// Uncomment if necessary
+//extern const UInt16 UnicodeCntrlBits[];
+//extern const UInt16 UnicodeGraphBits[];
+//extern const UInt16 UnicodeLowerBits[];
+//extern const UInt16 UnicodePrintBits[];
+//extern const UInt16 UnicodePunctBits[];
+//extern const UInt16 UnicodeUpperBits[];
+
+inline int OVR_CDECL OVR_iswalnum (wchar_t charCode) { return UnicodeCharIs(UnicodeAlnumBits, charCode); }
+inline int OVR_CDECL OVR_iswalpha (wchar_t charCode) { return UnicodeCharIs(UnicodeAlphaBits, charCode); }
+inline int OVR_CDECL OVR_iswdigit (wchar_t charCode) { return UnicodeCharIs(UnicodeDigitBits, charCode); }
+inline int OVR_CDECL OVR_iswspace (wchar_t charCode) { return UnicodeCharIs(UnicodeSpaceBits, charCode); }
+inline int OVR_CDECL OVR_iswxdigit(wchar_t charCode) { return UnicodeCharIs(UnicodeXDigitBits, charCode); }
+
+// Uncomment if necessary
+//inline int OVR_CDECL OVR_iswcntrl (wchar_t charCode) { return UnicodeCharIs(UnicodeCntrlBits, charCode); }
+//inline int OVR_CDECL OVR_iswgraph (wchar_t charCode) { return UnicodeCharIs(UnicodeGraphBits, charCode); }
+//inline int OVR_CDECL OVR_iswlower (wchar_t charCode) { return UnicodeCharIs(UnicodeLowerBits, charCode); }
+//inline int OVR_CDECL OVR_iswprint (wchar_t charCode) { return UnicodeCharIs(UnicodePrintBits, charCode); }
+//inline int OVR_CDECL OVR_iswpunct (wchar_t charCode) { return UnicodeCharIs(UnicodePunctBits, charCode); }
+//inline int OVR_CDECL OVR_iswupper (wchar_t charCode) { return UnicodeCharIs(UnicodeUpperBits, charCode); }
+
+int OVR_CDECL OVR_towupper(wchar_t charCode);
+int OVR_CDECL OVR_towlower(wchar_t charCode);
+
+#else // OVR_NO_WCTYPE
+
+inline int OVR_CDECL OVR_iswspace(wchar_t c)
+{
+ return iswspace(c);
+}
+
+inline int OVR_CDECL OVR_iswdigit(wchar_t c)
+{
+ return iswdigit(c);
+}
+
+inline int OVR_CDECL OVR_iswxdigit(wchar_t c)
+{
+ return iswxdigit(c);
+}
+
+inline int OVR_CDECL OVR_iswalpha(wchar_t c)
+{
+ return iswalpha(c);
+}
+
+inline int OVR_CDECL OVR_iswalnum(wchar_t c)
+{
+ return iswalnum(c);
+}
+
+inline wchar_t OVR_CDECL OVR_towlower(wchar_t c)
+{
+ return (wchar_t)towlower(c);
+}
+
+inline wchar_t OVR_towupper(wchar_t c)
+{
+ return (wchar_t)towupper(c);
+}
+
+#endif // OVR_NO_WCTYPE
+
+// ASCII versions of tolower and toupper. Don't use "char"
+inline int OVR_CDECL OVR_tolower(int c)
+{
+ return (c >= 'A' && c <= 'Z') ? c - 'A' + 'a' : c;
+}
+
+inline int OVR_CDECL OVR_toupper(int c)
+{
+ return (c >= 'a' && c <= 'z') ? c - 'a' + 'A' : c;
+}
+
+
+
+inline double OVR_CDECL OVR_wcstod(const wchar_t* string, wchar_t** tailptr)
+{
+#if defined(OVR_OS_OTHER)
+ OVR_UNUSED(tailptr);
+ char buffer[64];
+ char* tp = NULL;
+ UPInt max = OVR_wcslen(string);
+ if (max > 63) max = 63;
+ unsigned char c = 0;
+ for (UPInt i=0; i < max; i++)
+ {
+ c = (unsigned char)string[i];
+ buffer[i] = ((c) < 128 ? (char)c : '!');
+ }
+ buffer[max] = 0;
+ return OVR_strtod(buffer, &tp);
+#else
+ return wcstod(string, tailptr);
+#endif
+}
+
+inline long OVR_CDECL OVR_wcstol(const wchar_t* string, wchar_t** tailptr, int radix)
+{
+#if defined(OVR_OS_OTHER)
+ OVR_UNUSED(tailptr);
+ char buffer[64];
+ char* tp = NULL;
+ UPInt max = OVR_wcslen(string);
+ if (max > 63) max = 63;
+ unsigned char c = 0;
+ for (UPInt i=0; i < max; i++)
+ {
+ c = (unsigned char)string[i];
+ buffer[i] = ((c) < 128 ? (char)c : '!');
+ }
+ buffer[max] = 0;
+ return strtol(buffer, &tp, radix);
+#else
+ return wcstol(string, tailptr, radix);
+#endif
+}
+
+} // OVR
+
+#endif // OVR_Std_h
diff --git a/LibOVR/Src/Kernel/OVR_String.cpp b/LibOVR/Src/Kernel/OVR_String.cpp
index b591ede..4e5eb2e 100644
--- a/LibOVR/Src/Kernel/OVR_String.cpp
+++ b/LibOVR/Src/Kernel/OVR_String.cpp
@@ -1,752 +1,752 @@
-/************************************************************************************
-
-Filename : OVR_String.cpp
-Content : String UTF8 string implementation with copy-on-write semantics
- (thread-safe for assignment but not modification).
-Created : September 19, 2012
-Notes :
-
-Copyright : Copyright 2012 Oculus VR, Inc. All Rights reserved.
-
-Use of this software is subject to the terms of the Oculus license
-agreement provided at the time of installation or download, or which
-otherwise accompanies this software in either electronic or hard copy form.
-
-************************************************************************************/
-
-#include "OVR_String.h"
-
-#include <stdlib.h>
-#include <ctype.h>
-
-#ifdef OVR_OS_QNX
-# include <strings.h>
-#endif
-
-namespace OVR {
-
-#define String_LengthIsSize (UPInt(1) << String::Flag_LengthIsSizeShift)
-
-String::DataDesc String::NullData = {String_LengthIsSize, 1, {0} };
-
-
-String::String()
-{
- pData = &NullData;
- pData->AddRef();
-};
-
-String::String(const char* pdata)
-{
- // Obtain length in bytes; it doesn't matter if _data is UTF8.
- UPInt size = pdata ? OVR_strlen(pdata) : 0;
- pData = AllocDataCopy1(size, 0, pdata, size);
-};
-
-String::String(const char* pdata1, const char* pdata2, const char* pdata3)
-{
- // Obtain length in bytes; it doesn't matter if _data is UTF8.
- UPInt size1 = pdata1 ? OVR_strlen(pdata1) : 0;
- UPInt size2 = pdata2 ? OVR_strlen(pdata2) : 0;
- UPInt size3 = pdata3 ? OVR_strlen(pdata3) : 0;
-
- DataDesc *pdataDesc = AllocDataCopy2(size1 + size2 + size3, 0,
- pdata1, size1, pdata2, size2);
- memcpy(pdataDesc->Data + size1 + size2, pdata3, size3);
- pData = pdataDesc;
-}
-
-String::String(const char* pdata, UPInt size)
-{
- OVR_ASSERT((size == 0) || (pdata != 0));
- pData = AllocDataCopy1(size, 0, pdata, size);
-};
-
-
-String::String(const InitStruct& src, UPInt size)
-{
- pData = AllocData(size, 0);
- src.InitString(GetData()->Data, size);
-}
-
-String::String(const String& src)
-{
- pData = src.GetData();
- pData->AddRef();
-}
-
-String::String(const StringBuffer& src)
-{
- pData = AllocDataCopy1(src.GetSize(), 0, src.ToCStr(), src.GetSize());
-}
-
-String::String(const wchar_t* data)
-{
- pData = &NullData;
- pData->AddRef();
- // Simplified logic for wchar_t constructor.
- if (data)
- *this = data;
-}
-
-
-String::DataDesc* String::AllocData(UPInt size, UPInt lengthIsSize)
-{
- String::DataDesc* pdesc;
-
- if (size == 0)
- {
- pdesc = &NullData;
- pdesc->AddRef();
- return pdesc;
- }
-
- pdesc = (DataDesc*)OVR_ALLOC(sizeof(DataDesc)+ size);
- pdesc->Data[size] = 0;
- pdesc->RefCount = 1;
- pdesc->Size = size | lengthIsSize;
- return pdesc;
-}
-
-
-String::DataDesc* String::AllocDataCopy1(UPInt size, UPInt lengthIsSize,
- const char* pdata, UPInt copySize)
-{
- String::DataDesc* pdesc = AllocData(size, lengthIsSize);
- memcpy(pdesc->Data, pdata, copySize);
- return pdesc;
-}
-
-String::DataDesc* String::AllocDataCopy2(UPInt size, UPInt lengthIsSize,
- const char* pdata1, UPInt copySize1,
- const char* pdata2, UPInt copySize2)
-{
- String::DataDesc* pdesc = AllocData(size, lengthIsSize);
- memcpy(pdesc->Data, pdata1, copySize1);
- memcpy(pdesc->Data + copySize1, pdata2, copySize2);
- return pdesc;
-}
-
-
-UPInt String::GetLength() const
-{
- // Optimize length accesses for non-UTF8 character strings.
- DataDesc* pdata = GetData();
- UPInt length, size = pdata->GetSize();
-
- if (pdata->LengthIsSize())
- return size;
-
- length = (UPInt)UTF8Util::GetLength(pdata->Data, (UPInt)size);
-
- if (length == size)
- pdata->Size |= String_LengthIsSize;
-
- return length;
-}
-
-
-//static UInt32 String_CharSearch(const char* buf, )
-
-
-UInt32 String::GetCharAt(UPInt index) const
-{
- SPInt i = (SPInt) index;
- DataDesc* pdata = GetData();
- const char* buf = pdata->Data;
- UInt32 c;
-
- if (pdata->LengthIsSize())
- {
- OVR_ASSERT(index < pdata->GetSize());
- buf += i;
- return UTF8Util::DecodeNextChar_Advance0(&buf);
- }
-
- c = UTF8Util::GetCharAt(index, buf, pdata->GetSize());
- return c;
-}
-
-UInt32 String::GetFirstCharAt(UPInt index, const char** offset) const
-{
- DataDesc* pdata = GetData();
- SPInt i = (SPInt) index;
- const char* buf = pdata->Data;
- const char* end = buf + pdata->GetSize();
- UInt32 c;
-
- do
- {
- c = UTF8Util::DecodeNextChar_Advance0(&buf);
- i--;
-
- if (buf >= end)
- {
- // We've hit the end of the string; don't go further.
- OVR_ASSERT(i == 0);
- return c;
- }
- } while (i >= 0);
-
- *offset = buf;
-
- return c;
-}
-
-UInt32 String::GetNextChar(const char** offset) const
-{
- return UTF8Util::DecodeNextChar(offset);
-}
-
-
-
-void String::AppendChar(UInt32 ch)
-{
- DataDesc* pdata = GetData();
- UPInt size = pdata->GetSize();
- char buff[8];
- SPInt encodeSize = 0;
-
- // Converts ch into UTF8 string and fills it into buff.
- UTF8Util::EncodeChar(buff, &encodeSize, ch);
- OVR_ASSERT(encodeSize >= 0);
-
- SetData(AllocDataCopy2(size + (UPInt)encodeSize, 0,
- pdata->Data, size, buff, (UPInt)encodeSize));
- pdata->Release();
-}
-
-
-void String::AppendString(const wchar_t* pstr, SPInt len)
-{
- if (!pstr)
- return;
-
- DataDesc* pdata = GetData();
- UPInt oldSize = pdata->GetSize();
- UPInt encodeSize = (UPInt)UTF8Util::GetEncodeStringSize(pstr, len);
-
- DataDesc* pnewData = AllocDataCopy1(oldSize + (UPInt)encodeSize, 0,
- pdata->Data, oldSize);
- UTF8Util::EncodeString(pnewData->Data + oldSize, pstr, len);
-
- SetData(pnewData);
- pdata->Release();
-}
-
-
-void String::AppendString(const char* putf8str, SPInt utf8StrSz)
-{
- if (!putf8str || !utf8StrSz)
- return;
- if (utf8StrSz == -1)
- utf8StrSz = (SPInt)OVR_strlen(putf8str);
-
- DataDesc* pdata = GetData();
- UPInt oldSize = pdata->GetSize();
-
- SetData(AllocDataCopy2(oldSize + (UPInt)utf8StrSz, 0,
- pdata->Data, oldSize, putf8str, (UPInt)utf8StrSz));
- pdata->Release();
-}
-
-void String::AssignString(const InitStruct& src, UPInt size)
-{
- DataDesc* poldData = GetData();
- DataDesc* pnewData = AllocData(size, 0);
- src.InitString(pnewData->Data, size);
- SetData(pnewData);
- poldData->Release();
-}
-
-void String::AssignString(const char* putf8str, UPInt size)
-{
- DataDesc* poldData = GetData();
- SetData(AllocDataCopy1(size, 0, putf8str, size));
- poldData->Release();
-}
-
-void String::operator = (const char* pstr)
-{
- AssignString(pstr, pstr ? OVR_strlen(pstr) : 0);
-}
-
-void String::operator = (const wchar_t* pwstr)
-{
- DataDesc* poldData = GetData();
- UPInt size = pwstr ? (UPInt)UTF8Util::GetEncodeStringSize(pwstr) : 0;
-
- DataDesc* pnewData = AllocData(size, 0);
- UTF8Util::EncodeString(pnewData->Data, pwstr);
- SetData(pnewData);
- poldData->Release();
-}
-
-
-void String::operator = (const String& src)
-{
- DataDesc* psdata = src.GetData();
- DataDesc* pdata = GetData();
-
- SetData(psdata);
- psdata->AddRef();
- pdata->Release();
-}
-
-
-void String::operator = (const StringBuffer& src)
-{
- DataDesc* polddata = GetData();
- SetData(AllocDataCopy1(src.GetSize(), 0, src.ToCStr(), src.GetSize()));
- polddata->Release();
-}
-
-void String::operator += (const String& src)
-{
- DataDesc *pourData = GetData(),
- *psrcData = src.GetData();
- UPInt ourSize = pourData->GetSize(),
- srcSize = psrcData->GetSize();
- UPInt lflag = pourData->GetLengthFlag() & psrcData->GetLengthFlag();
-
- SetData(AllocDataCopy2(ourSize + srcSize, lflag,
- pourData->Data, ourSize, psrcData->Data, srcSize));
- pourData->Release();
-}
-
-
-String String::operator + (const char* str) const
-{
- String tmp1(*this);
- tmp1 += (str ? str : "");
- return tmp1;
-}
-
-String String::operator + (const String& src) const
-{
- String tmp1(*this);
- tmp1 += src;
- return tmp1;
-}
-
-void String::Remove(UPInt posAt, SPInt removeLength)
-{
- DataDesc* pdata = GetData();
- UPInt oldSize = pdata->GetSize();
- // Length indicates the number of characters to remove.
- UPInt length = GetLength();
-
- // If index is past the string, nothing to remove.
- if (posAt >= length)
- return;
- // Otherwise, cap removeLength to the length of the string.
- if ((posAt + removeLength) > length)
- removeLength = length - posAt;
-
- // Get the byte position of the UTF8 char at position posAt.
- SPInt bytePos = UTF8Util::GetByteIndex(posAt, pdata->Data, oldSize);
- SPInt removeSize = UTF8Util::GetByteIndex(removeLength, pdata->Data + bytePos, oldSize-bytePos);
-
- SetData(AllocDataCopy2(oldSize - removeSize, pdata->GetLengthFlag(),
- pdata->Data, bytePos,
- pData->Data + bytePos + removeSize, (oldSize - bytePos - removeSize)));
- pdata->Release();
-}
-
-
-String String::Substring(UPInt start, UPInt end) const
-{
- UPInt length = GetLength();
- if ((start >= length) || (start >= end))
- return String();
-
- DataDesc* pdata = GetData();
-
- // If size matches, we know the exact index range.
- if (pdata->LengthIsSize())
- return String(pdata->Data + start, end - start);
-
- // Get position of starting character.
- SPInt byteStart = UTF8Util::GetByteIndex(start, pdata->Data, pdata->GetSize());
- SPInt byteSize = UTF8Util::GetByteIndex(end - start, pdata->Data + byteStart, pdata->GetSize()-byteStart);
- return String(pdata->Data + byteStart, (UPInt)byteSize);
-}
-
-void String::Clear()
-{
- NullData.AddRef();
- GetData()->Release();
- SetData(&NullData);
-}
-
-
-String String::ToUpper() const
-{
- UInt32 c;
- const char* psource = GetData()->Data;
- const char* pend = psource + GetData()->GetSize();
- String str;
- SPInt bufferOffset = 0;
- char buffer[512];
-
- while(psource < pend)
- {
- do {
- c = UTF8Util::DecodeNextChar_Advance0(&psource);
- UTF8Util::EncodeChar(buffer, &bufferOffset, OVR_towupper(wchar_t(c)));
- } while ((psource < pend) && (bufferOffset < SPInt(sizeof(buffer)-8)));
-
- // Append string a piece at a time.
- str.AppendString(buffer, bufferOffset);
- bufferOffset = 0;
- }
-
- return str;
-}
-
-String String::ToLower() const
-{
- UInt32 c;
- const char* psource = GetData()->Data;
- const char* pend = psource + GetData()->GetSize();
- String str;
- SPInt bufferOffset = 0;
- char buffer[512];
-
- while(psource < pend)
- {
- do {
- c = UTF8Util::DecodeNextChar_Advance0(&psource);
- UTF8Util::EncodeChar(buffer, &bufferOffset, OVR_towlower(wchar_t(c)));
- } while ((psource < pend) && (bufferOffset < SPInt(sizeof(buffer)-8)));
-
- // Append string a piece at a time.
- str.AppendString(buffer, bufferOffset);
- bufferOffset = 0;
- }
-
- return str;
-}
-
-
-
-String& String::Insert(const char* substr, UPInt posAt, SPInt strSize)
-{
- DataDesc* poldData = GetData();
- UPInt oldSize = poldData->GetSize();
- UPInt insertSize = (strSize < 0) ? OVR_strlen(substr) : (UPInt)strSize;
- UPInt byteIndex = (poldData->LengthIsSize()) ?
- posAt : (UPInt)UTF8Util::GetByteIndex(posAt, poldData->Data, oldSize);
-
- OVR_ASSERT(byteIndex <= oldSize);
-
- DataDesc* pnewData = AllocDataCopy2(oldSize + insertSize, 0,
- poldData->Data, byteIndex, substr, insertSize);
- memcpy(pnewData->Data + byteIndex + insertSize,
- poldData->Data + byteIndex, oldSize - byteIndex);
- SetData(pnewData);
- poldData->Release();
- return *this;
-}
-
-/*
-String& String::Insert(const UInt32* substr, UPInt posAt, SPInt len)
-{
- for (SPInt i = 0; i < len; ++i)
- {
- UPInt charw = InsertCharAt(substr[i], posAt);
- posAt += charw;
- }
- return *this;
-}
-*/
-
-UPInt String::InsertCharAt(UInt32 c, UPInt posAt)
-{
- char buf[8];
- SPInt index = 0;
- UTF8Util::EncodeChar(buf, &index, c);
- OVR_ASSERT(index >= 0);
- buf[(UPInt)index] = 0;
-
- Insert(buf, posAt, index);
- return (UPInt)index;
-}
-
-
-int String::CompareNoCase(const char* a, const char* b)
-{
- return OVR_stricmp(a, b);
-}
-
-int String::CompareNoCase(const char* a, const char* b, SPInt len)
-{
- if (len)
- {
- SPInt f,l;
- SPInt slen = len;
- const char *s = b;
- do {
- f = (SPInt)OVR_tolower((int)(*(a++)));
- l = (SPInt)OVR_tolower((int)(*(b++)));
- } while (--len && f && (f == l) && *b != 0);
-
- if (f == l && (len != 0 || *b != 0))
- {
- f = (SPInt)slen;
- l = (SPInt)OVR_strlen(s);
- return int(f - l);
- }
-
- return int(f - l);
- }
- else
- return (0-(int)OVR_strlen(b));
-}
-
-// ***** Implement hash static functions
-
-// Hash function
-UPInt String::BernsteinHashFunction(const void* pdataIn, UPInt size, UPInt seed)
-{
- const UByte* pdata = (const UByte*) pdataIn;
- UPInt h = seed;
- while (size > 0)
- {
- size--;
- h = ((h << 5) + h) ^ (unsigned) pdata[size];
- }
-
- return h;
-}
-
-// Hash function, case-insensitive
-UPInt String::BernsteinHashFunctionCIS(const void* pdataIn, UPInt size, UPInt seed)
-{
- const UByte* pdata = (const UByte*) pdataIn;
- UPInt h = seed;
- while (size > 0)
- {
- size--;
- h = ((h << 5) + h) ^ OVR_tolower(pdata[size]);
- }
-
- // Alternative: "sdbm" hash function, suggested at same web page above.
- // h = 0;
- // for bytes { h = (h << 16) + (h << 6) - hash + *p; }
- return h;
-}
-
-
-
-// ***** String Buffer used for Building Strings
-
-
-#define OVR_SBUFF_DEFAULT_GROW_SIZE 512
-// Constructors / Destructor.
-StringBuffer::StringBuffer()
- : pData(NULL), Size(0), BufferSize(0), GrowSize(OVR_SBUFF_DEFAULT_GROW_SIZE), LengthIsSize(false)
-{
-}
-
-StringBuffer::StringBuffer(UPInt growSize)
- : pData(NULL), Size(0), BufferSize(0), GrowSize(OVR_SBUFF_DEFAULT_GROW_SIZE), LengthIsSize(false)
-{
- SetGrowSize(growSize);
-}
-
-StringBuffer::StringBuffer(const char* data)
- : pData(NULL), Size(0), BufferSize(0), GrowSize(OVR_SBUFF_DEFAULT_GROW_SIZE), LengthIsSize(false)
-{
- *this = data;
-}
-
-StringBuffer::StringBuffer(const char* data, UPInt dataSize)
- : pData(NULL), Size(0), BufferSize(0), GrowSize(OVR_SBUFF_DEFAULT_GROW_SIZE), LengthIsSize(false)
-{
- AppendString(data, dataSize);
-}
-
-StringBuffer::StringBuffer(const String& src)
- : pData(NULL), Size(0), BufferSize(0), GrowSize(OVR_SBUFF_DEFAULT_GROW_SIZE), LengthIsSize(false)
-{
- AppendString(src.ToCStr(), src.GetSize());
-}
-
-StringBuffer::StringBuffer(const StringBuffer& src)
- : pData(NULL), Size(0), BufferSize(src.GetGrowSize()), GrowSize(OVR_SBUFF_DEFAULT_GROW_SIZE), LengthIsSize(false)
-{
- AppendString(src.ToCStr(), src.GetSize());
- LengthIsSize = src.LengthIsSize;
-}
-
-StringBuffer::StringBuffer(const wchar_t* data)
- : pData(NULL), Size(0), BufferSize(0), GrowSize(OVR_SBUFF_DEFAULT_GROW_SIZE), LengthIsSize(false)
-{
- *this = data;
-}
-
-StringBuffer::~StringBuffer()
-{
- if (pData)
- OVR_FREE(pData);
-}
-void StringBuffer::SetGrowSize(UPInt growSize)
-{
- if (growSize <= 16)
- GrowSize = 16;
- else
- {
- UByte bits = Alg::UpperBit(UInt32(growSize-1));
- UPInt size = 1<<bits;
- GrowSize = size == growSize ? growSize : size;
- }
-}
-
-UPInt StringBuffer::GetLength() const
-{
- UPInt length, size = GetSize();
- if (LengthIsSize)
- return size;
-
- length = (UPInt)UTF8Util::GetLength(pData, (UPInt)GetSize());
-
- if (length == GetSize())
- LengthIsSize = true;
- return length;
-}
-
-void StringBuffer::Reserve(UPInt _size)
-{
- if (_size >= BufferSize) // >= because of trailing zero! (!AB)
- {
- BufferSize = (_size + 1 + GrowSize - 1)& ~(GrowSize-1);
- if (!pData)
- pData = (char*)OVR_ALLOC(BufferSize);
- else
- pData = (char*)OVR_REALLOC(pData, BufferSize);
- }
-}
-void StringBuffer::Resize(UPInt _size)
-{
- Reserve(_size);
- LengthIsSize = false;
- Size = _size;
- if (pData)
- pData[Size] = 0;
-}
-
-void StringBuffer::Clear()
-{
- Resize(0);
- /*
- if (pData != pEmptyNullData)
- {
- OVR_FREE(pHeap, pData);
- pData = pEmptyNullData;
- Size = BufferSize = 0;
- LengthIsSize = false;
- }
- */
-}
-// Appends a character
-void StringBuffer::AppendChar(UInt32 ch)
-{
- char buff[8];
- UPInt origSize = GetSize();
-
- // Converts ch into UTF8 string and fills it into buff. Also increments index according to the number of bytes
- // in the UTF8 string.
- SPInt srcSize = 0;
- UTF8Util::EncodeChar(buff, &srcSize, ch);
- OVR_ASSERT(srcSize >= 0);
-
- UPInt size = origSize + srcSize;
- Resize(size);
- memcpy(pData + origSize, buff, srcSize);
-}
-
-// Append a string
-void StringBuffer::AppendString(const wchar_t* pstr, SPInt len)
-{
- if (!pstr)
- return;
-
- SPInt srcSize = UTF8Util::GetEncodeStringSize(pstr, len);
- UPInt origSize = GetSize();
- UPInt size = srcSize + origSize;
-
- Resize(size);
- UTF8Util::EncodeString(pData + origSize, pstr, len);
-}
-
-void StringBuffer::AppendString(const char* putf8str, SPInt utf8StrSz)
-{
- if (!putf8str || !utf8StrSz)
- return;
- if (utf8StrSz == -1)
- utf8StrSz = (SPInt)OVR_strlen(putf8str);
-
- UPInt origSize = GetSize();
- UPInt size = utf8StrSz + origSize;
-
- Resize(size);
- memcpy(pData + origSize, putf8str, utf8StrSz);
-}
-
-
-void StringBuffer::operator = (const char* pstr)
-{
- pstr = pstr ? pstr : "";
- UPInt size = OVR_strlen(pstr);
- Resize(size);
- memcpy(pData, pstr, size);
-}
-
-void StringBuffer::operator = (const wchar_t* pstr)
-{
- pstr = pstr ? pstr : L"";
- UPInt size = (UPInt)UTF8Util::GetEncodeStringSize(pstr);
- Resize(size);
- UTF8Util::EncodeString(pData, pstr);
-}
-
-void StringBuffer::operator = (const String& src)
-{
- Resize(src.GetSize());
- memcpy(pData, src.ToCStr(), src.GetSize());
-}
-
-
-// Inserts substr at posAt
-void StringBuffer::Insert(const char* substr, UPInt posAt, SPInt len)
-{
- UPInt oldSize = Size;
- UPInt insertSize = (len < 0) ? OVR_strlen(substr) : (UPInt)len;
- UPInt byteIndex = LengthIsSize ? posAt :
- (UPInt)UTF8Util::GetByteIndex(posAt, pData, (SPInt)Size);
-
- OVR_ASSERT(byteIndex <= oldSize);
- Reserve(oldSize + insertSize);
-
- memmove(pData + byteIndex + insertSize, pData + byteIndex, oldSize - byteIndex + 1);
- memcpy (pData + byteIndex, substr, insertSize);
- LengthIsSize = false;
- Size = oldSize + insertSize;
- pData[Size] = 0;
-}
-
-// Inserts character at posAt
-UPInt StringBuffer::InsertCharAt(UInt32 c, UPInt posAt)
-{
- char buf[8];
- SPInt len = 0;
- UTF8Util::EncodeChar(buf, &len, c);
- OVR_ASSERT(len >= 0);
- buf[(UPInt)len] = 0;
-
- Insert(buf, posAt, len);
- return (UPInt)len;
-}
-
-} // OVR
+/************************************************************************************
+
+Filename : OVR_String.cpp
+Content : String UTF8 string implementation with copy-on-write semantics
+ (thread-safe for assignment but not modification).
+Created : September 19, 2012
+Notes :
+
+Copyright : Copyright 2012 Oculus VR, Inc. All Rights reserved.
+
+Use of this software is subject to the terms of the Oculus license
+agreement provided at the time of installation or download, or which
+otherwise accompanies this software in either electronic or hard copy form.
+
+************************************************************************************/
+
+#include "OVR_String.h"
+
+#include <stdlib.h>
+#include <ctype.h>
+
+#ifdef OVR_OS_QNX
+# include <strings.h>
+#endif
+
+namespace OVR {
+
+#define String_LengthIsSize (UPInt(1) << String::Flag_LengthIsSizeShift)
+
+String::DataDesc String::NullData = {String_LengthIsSize, 1, {0} };
+
+
+String::String()
+{
+ pData = &NullData;
+ pData->AddRef();
+};
+
+String::String(const char* pdata)
+{
+ // Obtain length in bytes; it doesn't matter if _data is UTF8.
+ UPInt size = pdata ? OVR_strlen(pdata) : 0;
+ pData = AllocDataCopy1(size, 0, pdata, size);
+};
+
+String::String(const char* pdata1, const char* pdata2, const char* pdata3)
+{
+ // Obtain length in bytes; it doesn't matter if _data is UTF8.
+ UPInt size1 = pdata1 ? OVR_strlen(pdata1) : 0;
+ UPInt size2 = pdata2 ? OVR_strlen(pdata2) : 0;
+ UPInt size3 = pdata3 ? OVR_strlen(pdata3) : 0;
+
+ DataDesc *pdataDesc = AllocDataCopy2(size1 + size2 + size3, 0,
+ pdata1, size1, pdata2, size2);
+ memcpy(pdataDesc->Data + size1 + size2, pdata3, size3);
+ pData = pdataDesc;
+}
+
+String::String(const char* pdata, UPInt size)
+{
+ OVR_ASSERT((size == 0) || (pdata != 0));
+ pData = AllocDataCopy1(size, 0, pdata, size);
+};
+
+
+String::String(const InitStruct& src, UPInt size)
+{
+ pData = AllocData(size, 0);
+ src.InitString(GetData()->Data, size);
+}
+
+String::String(const String& src)
+{
+ pData = src.GetData();
+ pData->AddRef();
+}
+
+String::String(const StringBuffer& src)
+{
+ pData = AllocDataCopy1(src.GetSize(), 0, src.ToCStr(), src.GetSize());
+}
+
+String::String(const wchar_t* data)
+{
+ pData = &NullData;
+ pData->AddRef();
+ // Simplified logic for wchar_t constructor.
+ if (data)
+ *this = data;
+}
+
+
+String::DataDesc* String::AllocData(UPInt size, UPInt lengthIsSize)
+{
+ String::DataDesc* pdesc;
+
+ if (size == 0)
+ {
+ pdesc = &NullData;
+ pdesc->AddRef();
+ return pdesc;
+ }
+
+ pdesc = (DataDesc*)OVR_ALLOC(sizeof(DataDesc)+ size);
+ pdesc->Data[size] = 0;
+ pdesc->RefCount = 1;
+ pdesc->Size = size | lengthIsSize;
+ return pdesc;
+}
+
+
+String::DataDesc* String::AllocDataCopy1(UPInt size, UPInt lengthIsSize,
+ const char* pdata, UPInt copySize)
+{
+ String::DataDesc* pdesc = AllocData(size, lengthIsSize);
+ memcpy(pdesc->Data, pdata, copySize);
+ return pdesc;
+}
+
+String::DataDesc* String::AllocDataCopy2(UPInt size, UPInt lengthIsSize,
+ const char* pdata1, UPInt copySize1,
+ const char* pdata2, UPInt copySize2)
+{
+ String::DataDesc* pdesc = AllocData(size, lengthIsSize);
+ memcpy(pdesc->Data, pdata1, copySize1);
+ memcpy(pdesc->Data + copySize1, pdata2, copySize2);
+ return pdesc;
+}
+
+
+UPInt String::GetLength() const
+{
+ // Optimize length accesses for non-UTF8 character strings.
+ DataDesc* pdata = GetData();
+ UPInt length, size = pdata->GetSize();
+
+ if (pdata->LengthIsSize())
+ return size;
+
+ length = (UPInt)UTF8Util::GetLength(pdata->Data, (UPInt)size);
+
+ if (length == size)
+ pdata->Size |= String_LengthIsSize;
+
+ return length;
+}
+
+
+//static UInt32 String_CharSearch(const char* buf, )
+
+
+UInt32 String::GetCharAt(UPInt index) const
+{
+ SPInt i = (SPInt) index;
+ DataDesc* pdata = GetData();
+ const char* buf = pdata->Data;
+ UInt32 c;
+
+ if (pdata->LengthIsSize())
+ {
+ OVR_ASSERT(index < pdata->GetSize());
+ buf += i;
+ return UTF8Util::DecodeNextChar_Advance0(&buf);
+ }
+
+ c = UTF8Util::GetCharAt(index, buf, pdata->GetSize());
+ return c;
+}
+
+UInt32 String::GetFirstCharAt(UPInt index, const char** offset) const
+{
+ DataDesc* pdata = GetData();
+ SPInt i = (SPInt) index;
+ const char* buf = pdata->Data;
+ const char* end = buf + pdata->GetSize();
+ UInt32 c;
+
+ do
+ {
+ c = UTF8Util::DecodeNextChar_Advance0(&buf);
+ i--;
+
+ if (buf >= end)
+ {
+ // We've hit the end of the string; don't go further.
+ OVR_ASSERT(i == 0);
+ return c;
+ }
+ } while (i >= 0);
+
+ *offset = buf;
+
+ return c;
+}
+
+UInt32 String::GetNextChar(const char** offset) const
+{
+ return UTF8Util::DecodeNextChar(offset);
+}
+
+
+
+void String::AppendChar(UInt32 ch)
+{
+ DataDesc* pdata = GetData();
+ UPInt size = pdata->GetSize();
+ char buff[8];
+ SPInt encodeSize = 0;
+
+ // Converts ch into UTF8 string and fills it into buff.
+ UTF8Util::EncodeChar(buff, &encodeSize, ch);
+ OVR_ASSERT(encodeSize >= 0);
+
+ SetData(AllocDataCopy2(size + (UPInt)encodeSize, 0,
+ pdata->Data, size, buff, (UPInt)encodeSize));
+ pdata->Release();
+}
+
+
+void String::AppendString(const wchar_t* pstr, SPInt len)
+{
+ if (!pstr)
+ return;
+
+ DataDesc* pdata = GetData();
+ UPInt oldSize = pdata->GetSize();
+ UPInt encodeSize = (UPInt)UTF8Util::GetEncodeStringSize(pstr, len);
+
+ DataDesc* pnewData = AllocDataCopy1(oldSize + (UPInt)encodeSize, 0,
+ pdata->Data, oldSize);
+ UTF8Util::EncodeString(pnewData->Data + oldSize, pstr, len);
+
+ SetData(pnewData);
+ pdata->Release();
+}
+
+
+void String::AppendString(const char* putf8str, SPInt utf8StrSz)
+{
+ if (!putf8str || !utf8StrSz)
+ return;
+ if (utf8StrSz == -1)
+ utf8StrSz = (SPInt)OVR_strlen(putf8str);
+
+ DataDesc* pdata = GetData();
+ UPInt oldSize = pdata->GetSize();
+
+ SetData(AllocDataCopy2(oldSize + (UPInt)utf8StrSz, 0,
+ pdata->Data, oldSize, putf8str, (UPInt)utf8StrSz));
+ pdata->Release();
+}
+
+void String::AssignString(const InitStruct& src, UPInt size)
+{
+ DataDesc* poldData = GetData();
+ DataDesc* pnewData = AllocData(size, 0);
+ src.InitString(pnewData->Data, size);
+ SetData(pnewData);
+ poldData->Release();
+}
+
+void String::AssignString(const char* putf8str, UPInt size)
+{
+ DataDesc* poldData = GetData();
+ SetData(AllocDataCopy1(size, 0, putf8str, size));
+ poldData->Release();
+}
+
+void String::operator = (const char* pstr)
+{
+ AssignString(pstr, pstr ? OVR_strlen(pstr) : 0);
+}
+
+void String::operator = (const wchar_t* pwstr)
+{
+ DataDesc* poldData = GetData();
+ UPInt size = pwstr ? (UPInt)UTF8Util::GetEncodeStringSize(pwstr) : 0;
+
+ DataDesc* pnewData = AllocData(size, 0);
+ UTF8Util::EncodeString(pnewData->Data, pwstr);
+ SetData(pnewData);
+ poldData->Release();
+}
+
+
+void String::operator = (const String& src)
+{
+ DataDesc* psdata = src.GetData();
+ DataDesc* pdata = GetData();
+
+ SetData(psdata);
+ psdata->AddRef();
+ pdata->Release();
+}
+
+
+void String::operator = (const StringBuffer& src)
+{
+ DataDesc* polddata = GetData();
+ SetData(AllocDataCopy1(src.GetSize(), 0, src.ToCStr(), src.GetSize()));
+ polddata->Release();
+}
+
+void String::operator += (const String& src)
+{
+ DataDesc *pourData = GetData(),
+ *psrcData = src.GetData();
+ UPInt ourSize = pourData->GetSize(),
+ srcSize = psrcData->GetSize();
+ UPInt lflag = pourData->GetLengthFlag() & psrcData->GetLengthFlag();
+
+ SetData(AllocDataCopy2(ourSize + srcSize, lflag,
+ pourData->Data, ourSize, psrcData->Data, srcSize));
+ pourData->Release();
+}
+
+
+String String::operator + (const char* str) const
+{
+ String tmp1(*this);
+ tmp1 += (str ? str : "");
+ return tmp1;
+}
+
+String String::operator + (const String& src) const
+{
+ String tmp1(*this);
+ tmp1 += src;
+ return tmp1;
+}
+
+void String::Remove(UPInt posAt, SPInt removeLength)
+{
+ DataDesc* pdata = GetData();
+ UPInt oldSize = pdata->GetSize();
+ // Length indicates the number of characters to remove.
+ UPInt length = GetLength();
+
+ // If index is past the string, nothing to remove.
+ if (posAt >= length)
+ return;
+ // Otherwise, cap removeLength to the length of the string.
+ if ((posAt + removeLength) > length)
+ removeLength = length - posAt;
+
+ // Get the byte position of the UTF8 char at position posAt.
+ SPInt bytePos = UTF8Util::GetByteIndex(posAt, pdata->Data, oldSize);
+ SPInt removeSize = UTF8Util::GetByteIndex(removeLength, pdata->Data + bytePos, oldSize-bytePos);
+
+ SetData(AllocDataCopy2(oldSize - removeSize, pdata->GetLengthFlag(),
+ pdata->Data, bytePos,
+ pData->Data + bytePos + removeSize, (oldSize - bytePos - removeSize)));
+ pdata->Release();
+}
+
+
+String String::Substring(UPInt start, UPInt end) const
+{
+ UPInt length = GetLength();
+ if ((start >= length) || (start >= end))
+ return String();
+
+ DataDesc* pdata = GetData();
+
+ // If size matches, we know the exact index range.
+ if (pdata->LengthIsSize())
+ return String(pdata->Data + start, end - start);
+
+ // Get position of starting character.
+ SPInt byteStart = UTF8Util::GetByteIndex(start, pdata->Data, pdata->GetSize());
+ SPInt byteSize = UTF8Util::GetByteIndex(end - start, pdata->Data + byteStart, pdata->GetSize()-byteStart);
+ return String(pdata->Data + byteStart, (UPInt)byteSize);
+}
+
+void String::Clear()
+{
+ NullData.AddRef();
+ GetData()->Release();
+ SetData(&NullData);
+}
+
+
+String String::ToUpper() const
+{
+ UInt32 c;
+ const char* psource = GetData()->Data;
+ const char* pend = psource + GetData()->GetSize();
+ String str;
+ SPInt bufferOffset = 0;
+ char buffer[512];
+
+ while(psource < pend)
+ {
+ do {
+ c = UTF8Util::DecodeNextChar_Advance0(&psource);
+ UTF8Util::EncodeChar(buffer, &bufferOffset, OVR_towupper(wchar_t(c)));
+ } while ((psource < pend) && (bufferOffset < SPInt(sizeof(buffer)-8)));
+
+ // Append string a piece at a time.
+ str.AppendString(buffer, bufferOffset);
+ bufferOffset = 0;
+ }
+
+ return str;
+}
+
+String String::ToLower() const
+{
+ UInt32 c;
+ const char* psource = GetData()->Data;
+ const char* pend = psource + GetData()->GetSize();
+ String str;
+ SPInt bufferOffset = 0;
+ char buffer[512];
+
+ while(psource < pend)
+ {
+ do {
+ c = UTF8Util::DecodeNextChar_Advance0(&psource);
+ UTF8Util::EncodeChar(buffer, &bufferOffset, OVR_towlower(wchar_t(c)));
+ } while ((psource < pend) && (bufferOffset < SPInt(sizeof(buffer)-8)));
+
+ // Append string a piece at a time.
+ str.AppendString(buffer, bufferOffset);
+ bufferOffset = 0;
+ }
+
+ return str;
+}
+
+
+
+String& String::Insert(const char* substr, UPInt posAt, SPInt strSize)
+{
+ DataDesc* poldData = GetData();
+ UPInt oldSize = poldData->GetSize();
+ UPInt insertSize = (strSize < 0) ? OVR_strlen(substr) : (UPInt)strSize;
+ UPInt byteIndex = (poldData->LengthIsSize()) ?
+ posAt : (UPInt)UTF8Util::GetByteIndex(posAt, poldData->Data, oldSize);
+
+ OVR_ASSERT(byteIndex <= oldSize);
+
+ DataDesc* pnewData = AllocDataCopy2(oldSize + insertSize, 0,
+ poldData->Data, byteIndex, substr, insertSize);
+ memcpy(pnewData->Data + byteIndex + insertSize,
+ poldData->Data + byteIndex, oldSize - byteIndex);
+ SetData(pnewData);
+ poldData->Release();
+ return *this;
+}
+
+/*
+String& String::Insert(const UInt32* substr, UPInt posAt, SPInt len)
+{
+ for (SPInt i = 0; i < len; ++i)
+ {
+ UPInt charw = InsertCharAt(substr[i], posAt);
+ posAt += charw;
+ }
+ return *this;
+}
+*/
+
+UPInt String::InsertCharAt(UInt32 c, UPInt posAt)
+{
+ char buf[8];
+ SPInt index = 0;
+ UTF8Util::EncodeChar(buf, &index, c);
+ OVR_ASSERT(index >= 0);
+ buf[(UPInt)index] = 0;
+
+ Insert(buf, posAt, index);
+ return (UPInt)index;
+}
+
+
+int String::CompareNoCase(const char* a, const char* b)
+{
+ return OVR_stricmp(a, b);
+}
+
+int String::CompareNoCase(const char* a, const char* b, SPInt len)
+{
+ if (len)
+ {
+ SPInt f,l;
+ SPInt slen = len;
+ const char *s = b;
+ do {
+ f = (SPInt)OVR_tolower((int)(*(a++)));
+ l = (SPInt)OVR_tolower((int)(*(b++)));
+ } while (--len && f && (f == l) && *b != 0);
+
+ if (f == l && (len != 0 || *b != 0))
+ {
+ f = (SPInt)slen;
+ l = (SPInt)OVR_strlen(s);
+ return int(f - l);
+ }
+
+ return int(f - l);
+ }
+ else
+ return (0-(int)OVR_strlen(b));
+}
+
+// ***** Implement hash static functions
+
+// Hash function
+UPInt String::BernsteinHashFunction(const void* pdataIn, UPInt size, UPInt seed)
+{
+ const UByte* pdata = (const UByte*) pdataIn;
+ UPInt h = seed;
+ while (size > 0)
+ {
+ size--;
+ h = ((h << 5) + h) ^ (unsigned) pdata[size];
+ }
+
+ return h;
+}
+
+// Hash function, case-insensitive
+UPInt String::BernsteinHashFunctionCIS(const void* pdataIn, UPInt size, UPInt seed)
+{
+ const UByte* pdata = (const UByte*) pdataIn;
+ UPInt h = seed;
+ while (size > 0)
+ {
+ size--;
+ h = ((h << 5) + h) ^ OVR_tolower(pdata[size]);
+ }
+
+ // Alternative: "sdbm" hash function, suggested at same web page above.
+ // h = 0;
+ // for bytes { h = (h << 16) + (h << 6) - hash + *p; }
+ return h;
+}
+
+
+
+// ***** String Buffer used for Building Strings
+
+
+#define OVR_SBUFF_DEFAULT_GROW_SIZE 512
+// Constructors / Destructor.
+StringBuffer::StringBuffer()
+ : pData(NULL), Size(0), BufferSize(0), GrowSize(OVR_SBUFF_DEFAULT_GROW_SIZE), LengthIsSize(false)
+{
+}
+
+StringBuffer::StringBuffer(UPInt growSize)
+ : pData(NULL), Size(0), BufferSize(0), GrowSize(OVR_SBUFF_DEFAULT_GROW_SIZE), LengthIsSize(false)
+{
+ SetGrowSize(growSize);
+}
+
+StringBuffer::StringBuffer(const char* data)
+ : pData(NULL), Size(0), BufferSize(0), GrowSize(OVR_SBUFF_DEFAULT_GROW_SIZE), LengthIsSize(false)
+{
+ *this = data;
+}
+
+StringBuffer::StringBuffer(const char* data, UPInt dataSize)
+ : pData(NULL), Size(0), BufferSize(0), GrowSize(OVR_SBUFF_DEFAULT_GROW_SIZE), LengthIsSize(false)
+{
+ AppendString(data, dataSize);
+}
+
+StringBuffer::StringBuffer(const String& src)
+ : pData(NULL), Size(0), BufferSize(0), GrowSize(OVR_SBUFF_DEFAULT_GROW_SIZE), LengthIsSize(false)
+{
+ AppendString(src.ToCStr(), src.GetSize());
+}
+
+StringBuffer::StringBuffer(const StringBuffer& src)
+ : pData(NULL), Size(0), BufferSize(src.GetGrowSize()), GrowSize(OVR_SBUFF_DEFAULT_GROW_SIZE), LengthIsSize(false)
+{
+ AppendString(src.ToCStr(), src.GetSize());
+ LengthIsSize = src.LengthIsSize;
+}
+
+StringBuffer::StringBuffer(const wchar_t* data)
+ : pData(NULL), Size(0), BufferSize(0), GrowSize(OVR_SBUFF_DEFAULT_GROW_SIZE), LengthIsSize(false)
+{
+ *this = data;
+}
+
+StringBuffer::~StringBuffer()
+{
+ if (pData)
+ OVR_FREE(pData);
+}
+void StringBuffer::SetGrowSize(UPInt growSize)
+{
+ if (growSize <= 16)
+ GrowSize = 16;
+ else
+ {
+ UByte bits = Alg::UpperBit(UInt32(growSize-1));
+ UPInt size = 1<<bits;
+ GrowSize = size == growSize ? growSize : size;
+ }
+}
+
+UPInt StringBuffer::GetLength() const
+{
+ UPInt length, size = GetSize();
+ if (LengthIsSize)
+ return size;
+
+ length = (UPInt)UTF8Util::GetLength(pData, (UPInt)GetSize());
+
+ if (length == GetSize())
+ LengthIsSize = true;
+ return length;
+}
+
+void StringBuffer::Reserve(UPInt _size)
+{
+ if (_size >= BufferSize) // >= because of trailing zero! (!AB)
+ {
+ BufferSize = (_size + 1 + GrowSize - 1)& ~(GrowSize-1);
+ if (!pData)
+ pData = (char*)OVR_ALLOC(BufferSize);
+ else
+ pData = (char*)OVR_REALLOC(pData, BufferSize);
+ }
+}
+void StringBuffer::Resize(UPInt _size)
+{
+ Reserve(_size);
+ LengthIsSize = false;
+ Size = _size;
+ if (pData)
+ pData[Size] = 0;
+}
+
+void StringBuffer::Clear()
+{
+ Resize(0);
+ /*
+ if (pData != pEmptyNullData)
+ {
+ OVR_FREE(pHeap, pData);
+ pData = pEmptyNullData;
+ Size = BufferSize = 0;
+ LengthIsSize = false;
+ }
+ */
+}
+// Appends a character
+void StringBuffer::AppendChar(UInt32 ch)
+{
+ char buff[8];
+ UPInt origSize = GetSize();
+
+ // Converts ch into UTF8 string and fills it into buff. Also increments index according to the number of bytes
+ // in the UTF8 string.
+ SPInt srcSize = 0;
+ UTF8Util::EncodeChar(buff, &srcSize, ch);
+ OVR_ASSERT(srcSize >= 0);
+
+ UPInt size = origSize + srcSize;
+ Resize(size);
+ memcpy(pData + origSize, buff, srcSize);
+}
+
+// Append a string
+void StringBuffer::AppendString(const wchar_t* pstr, SPInt len)
+{
+ if (!pstr)
+ return;
+
+ SPInt srcSize = UTF8Util::GetEncodeStringSize(pstr, len);
+ UPInt origSize = GetSize();
+ UPInt size = srcSize + origSize;
+
+ Resize(size);
+ UTF8Util::EncodeString(pData + origSize, pstr, len);
+}
+
+void StringBuffer::AppendString(const char* putf8str, SPInt utf8StrSz)
+{
+ if (!putf8str || !utf8StrSz)
+ return;
+ if (utf8StrSz == -1)
+ utf8StrSz = (SPInt)OVR_strlen(putf8str);
+
+ UPInt origSize = GetSize();
+ UPInt size = utf8StrSz + origSize;
+
+ Resize(size);
+ memcpy(pData + origSize, putf8str, utf8StrSz);
+}
+
+
+void StringBuffer::operator = (const char* pstr)
+{
+ pstr = pstr ? pstr : "";
+ UPInt size = OVR_strlen(pstr);
+ Resize(size);
+ memcpy(pData, pstr, size);
+}
+
+void StringBuffer::operator = (const wchar_t* pstr)
+{
+ pstr = pstr ? pstr : L"";
+ UPInt size = (UPInt)UTF8Util::GetEncodeStringSize(pstr);
+ Resize(size);
+ UTF8Util::EncodeString(pData, pstr);
+}
+
+void StringBuffer::operator = (const String& src)
+{
+ Resize(src.GetSize());
+ memcpy(pData, src.ToCStr(), src.GetSize());
+}
+
+
+// Inserts substr at posAt
+void StringBuffer::Insert(const char* substr, UPInt posAt, SPInt len)
+{
+ UPInt oldSize = Size;
+ UPInt insertSize = (len < 0) ? OVR_strlen(substr) : (UPInt)len;
+ UPInt byteIndex = LengthIsSize ? posAt :
+ (UPInt)UTF8Util::GetByteIndex(posAt, pData, (SPInt)Size);
+
+ OVR_ASSERT(byteIndex <= oldSize);
+ Reserve(oldSize + insertSize);
+
+ memmove(pData + byteIndex + insertSize, pData + byteIndex, oldSize - byteIndex + 1);
+ memcpy (pData + byteIndex, substr, insertSize);
+ LengthIsSize = false;
+ Size = oldSize + insertSize;
+ pData[Size] = 0;
+}
+
+// Inserts character at posAt
+UPInt StringBuffer::InsertCharAt(UInt32 c, UPInt posAt)
+{
+ char buf[8];
+ SPInt len = 0;
+ UTF8Util::EncodeChar(buf, &len, c);
+ OVR_ASSERT(len >= 0);
+ buf[(UPInt)len] = 0;
+
+ Insert(buf, posAt, len);
+ return (UPInt)len;
+}
+
+} // OVR
diff --git a/LibOVR/Src/Kernel/OVR_String.h b/LibOVR/Src/Kernel/OVR_String.h
index 112878c..794990f 100644
--- a/LibOVR/Src/Kernel/OVR_String.h
+++ b/LibOVR/Src/Kernel/OVR_String.h
@@ -1,645 +1,645 @@
-/************************************************************************************
-
-PublicHeader: OVR.h
-Filename : OVR_String.h
-Content : String UTF8 string implementation with copy-on-write semantics
- (thread-safe for assignment but not modification).
-Created : September 19, 2012
-Notes :
-
-Copyright : Copyright 2012 Oculus VR, Inc. All Rights reserved.
-
-Use of this software is subject to the terms of the Oculus license
-agreement provided at the time of installation or download, or which
-otherwise accompanies this software in either electronic or hard copy form.
-
-************************************************************************************/
-
-#ifndef OVR_String_h
-#define OVR_String_h
-
-#include "OVR_Types.h"
-#include "OVR_Allocator.h"
-#include "OVR_UTF8Util.h"
-#include "OVR_Atomic.h"
-#include "OVR_Std.h"
-#include "OVR_Alg.h"
-
-namespace OVR {
-
-// ***** Classes
-
-class String;
-class StringBuffer;
-
-
-//-----------------------------------------------------------------------------------
-// ***** String Class
-
-// String is UTF8 based string class with copy-on-write implementation
-// for assignment.
-
-class String
-{
-protected:
-
- enum FlagConstants
- {
- //Flag_GetLength = 0x7FFFFFFF,
- // This flag is set if GetLength() == GetSize() for a string.
- // Avoid extra scanning is Substring and indexing logic.
- Flag_LengthIsSizeShift = (sizeof(UPInt)*8 - 1)
- };
-
-
- // Internal structure to hold string data
- struct DataDesc
- {
- // Number of bytes. Will be the same as the number of chars if the characters
- // are ascii, may not be equal to number of chars in case string data is UTF8.
- UPInt Size;
- volatile SInt32 RefCount;
- char Data[1];
-
- void AddRef()
- {
- AtomicOps<SInt32>::ExchangeAdd_NoSync(&RefCount, 1);
- }
- // Decrement ref count. This needs to be thread-safe, since
- // a different thread could have also decremented the ref count.
- // For example, if u start off with a ref count = 2. Now if u
- // decrement the ref count and check against 0 in different
- // statements, a different thread can also decrement the ref count
- // in between our decrement and checking against 0 and will find
- // the ref count = 0 and delete the object. This will lead to a crash
- // when context switches to our thread and we'll be trying to delete
- // an already deleted object. Hence decrementing the ref count and
- // checking against 0 needs to made an atomic operation.
- void Release()
- {
- if ((AtomicOps<SInt32>::ExchangeAdd_NoSync(&RefCount, -1) - 1) == 0)
- OVR_FREE(this);
- }
-
- static UPInt GetLengthFlagBit() { return UPInt(1) << Flag_LengthIsSizeShift; }
- UPInt GetSize() const { return Size & ~GetLengthFlagBit() ; }
- UPInt GetLengthFlag() const { return Size & GetLengthFlagBit(); }
- bool LengthIsSize() const { return GetLengthFlag() != 0; }
- };
-
- // Heap type of the string is encoded in the lower bits.
- enum HeapType
- {
- HT_Global = 0, // Heap is global.
- HT_Local = 1, // SF::String_loc: Heap is determined based on string's address.
- HT_Dynamic = 2, // SF::String_temp: Heap is stored as a part of the class.
- HT_Mask = 3
- };
-
- union {
- DataDesc* pData;
- UPInt HeapTypeBits;
- };
- typedef union {
- DataDesc* pData;
- UPInt HeapTypeBits;
- } DataDescUnion;
-
- inline HeapType GetHeapType() const { return (HeapType) (HeapTypeBits & HT_Mask); }
-
- inline DataDesc* GetData() const
- {
- DataDescUnion u;
- u.pData = pData;
- u.HeapTypeBits = (u.HeapTypeBits & ~(UPInt)HT_Mask);
- return u.pData;
- }
-
- inline void SetData(DataDesc* pdesc)
- {
- HeapType ht = GetHeapType();
- pData = pdesc;
- OVR_ASSERT((HeapTypeBits & HT_Mask) == 0);
- HeapTypeBits |= ht;
- }
-
-
- DataDesc* AllocData(UPInt size, UPInt lengthIsSize);
- DataDesc* AllocDataCopy1(UPInt size, UPInt lengthIsSize,
- const char* pdata, UPInt copySize);
- DataDesc* AllocDataCopy2(UPInt size, UPInt lengthIsSize,
- const char* pdata1, UPInt copySize1,
- const char* pdata2, UPInt copySize2);
-
- // Special constructor to avoid data initalization when used in derived class.
- struct NoConstructor { };
- String(const NoConstructor&) { }
-
-public:
-
- // For initializing string with dynamic buffer
- struct InitStruct
- {
- virtual ~InitStruct() { }
- virtual void InitString(char* pbuffer, UPInt size) const = 0;
- };
-
-
- // Constructors / Destructors.
- String();
- String(const char* data);
- String(const char* data1, const char* pdata2, const char* pdata3 = 0);
- String(const char* data, UPInt buflen);
- String(const String& src);
- String(const StringBuffer& src);
- String(const InitStruct& src, UPInt size);
- explicit String(const wchar_t* data);
-
- // Destructor (Captain Obvious guarantees!)
- ~String()
- {
- GetData()->Release();
- }
-
- // Declaration of NullString
- static DataDesc NullData;
-
-
- // *** General Functions
-
- void Clear();
-
- // For casting to a pointer to char.
- operator const char*() const { return GetData()->Data; }
- // Pointer to raw buffer.
- const char* ToCStr() const { return GetData()->Data; }
-
- // Returns number of bytes
- UPInt GetSize() const { return GetData()->GetSize() ; }
- // Tells whether or not the string is empty
- bool IsEmpty() const { return GetSize() == 0; }
-
- // Returns number of characters
- UPInt GetLength() const;
-
- // Returns character at the specified index
- UInt32 GetCharAt(UPInt index) const;
- UInt32 GetFirstCharAt(UPInt index, const char** offset) const;
- UInt32 GetNextChar(const char** offset) const;
-
- // Appends a character
- void AppendChar(UInt32 ch);
-
- // Append a string
- void AppendString(const wchar_t* pstr, SPInt len = -1);
- void AppendString(const char* putf8str, SPInt utf8StrSz = -1);
-
- // Assigned a string with dynamic data (copied through initializer).
- void AssignString(const InitStruct& src, UPInt size);
- // Assigns string with known size.
- void AssignString(const char* putf8str, UPInt size);
-
- // Resize the string to the new size
-// void Resize(UPInt _size);
-
- // Removes the character at posAt
- void Remove(UPInt posAt, SPInt len = 1);
-
- // Returns a String that's a substring of this.
- // -start is the index of the first UTF8 character you want to include.
- // -end is the index one past the last UTF8 character you want to include.
- String Substring(UPInt start, UPInt end) const;
-
- // Case-conversion
- String ToUpper() const;
- String ToLower() const;
-
- // Inserts substr at posAt
- String& Insert (const char* substr, UPInt posAt, SPInt len = -1);
-
- // Inserts character at posAt
- UPInt InsertCharAt(UInt32 c, UPInt posAt);
-
- // Inserts substr at posAt, which is an index of a character (not byte).
- // Of size is specified, it is in bytes.
-// String& Insert(const UInt32* substr, UPInt posAt, SPInt size = -1);
-
- // Get Byte index of the character at position = index
- UPInt GetByteIndex(UPInt index) const { return (UPInt)UTF8Util::GetByteIndex(index, GetData()->Data); }
-
- // Utility: case-insensitive string compare. stricmp() & strnicmp() are not
- // ANSI or POSIX, do not seem to appear in Linux.
- static int OVR_STDCALL CompareNoCase(const char* a, const char* b);
- static int OVR_STDCALL CompareNoCase(const char* a, const char* b, SPInt len);
-
- // Hash function, case-insensitive
- static UPInt OVR_STDCALL BernsteinHashFunctionCIS(const void* pdataIn, UPInt size, UPInt seed = 5381);
-
- // Hash function, case-sensitive
- static UPInt OVR_STDCALL BernsteinHashFunction(const void* pdataIn, UPInt size, UPInt seed = 5381);
-
-
- // ***** File path parsing helper functions.
- // Implemented in OVR_String_FilePath.cpp.
-
- // Absolute paths can star with:
- // - protocols: 'file://', 'http://'
- // - windows drive: 'c:\'
- // - UNC share name: '\\share'
- // - unix root '/'
- static bool HasAbsolutePath(const char* path);
- static bool HasExtension(const char* path);
- static bool HasProtocol(const char* path);
-
- bool HasAbsolutePath() const { return HasAbsolutePath(ToCStr()); }
- bool HasExtension() const { return HasExtension(ToCStr()); }
- bool HasProtocol() const { return HasProtocol(ToCStr()); }
-
- String GetProtocol() const; // Returns protocol, if any, with trailing '://'.
- String GetPath() const; // Returns path with trailing '/'.
- String GetFilename() const; // Returns filename, including extension.
- String GetExtension() const; // Returns extension with a dot.
-
- void StripProtocol(); // Strips front protocol, if any, from the string.
- void StripExtension(); // Strips off trailing extension.
-
-
- // Operators
- // Assignment
- void operator = (const char* str);
- void operator = (const wchar_t* str);
- void operator = (const String& src);
- void operator = (const StringBuffer& src);
-
- // Addition
- void operator += (const String& src);
- void operator += (const char* psrc) { AppendString(psrc); }
- void operator += (const wchar_t* psrc) { AppendString(psrc); }
- void operator += (char ch) { AppendChar(ch); }
- String operator + (const char* str) const;
- String operator + (const String& src) const;
-
- // Comparison
- bool operator == (const String& str) const
- {
- return (OVR_strcmp(GetData()->Data, str.GetData()->Data)== 0);
- }
-
- bool operator != (const String& str) const
- {
- return !operator == (str);
- }
-
- bool operator == (const char* str) const
- {
- return OVR_strcmp(GetData()->Data, str) == 0;
- }
-
- bool operator != (const char* str) const
- {
- return !operator == (str);
- }
-
- bool operator < (const char* pstr) const
- {
- return OVR_strcmp(GetData()->Data, pstr) < 0;
- }
-
- bool operator < (const String& str) const
- {
- return *this < str.GetData()->Data;
- }
-
- bool operator > (const char* pstr) const
- {
- return OVR_strcmp(GetData()->Data, pstr) > 0;
- }
-
- bool operator > (const String& str) const
- {
- return *this > str.GetData()->Data;
- }
-
- int CompareNoCase(const char* pstr) const
- {
- return CompareNoCase(GetData()->Data, pstr);
- }
- int CompareNoCase(const String& str) const
- {
- return CompareNoCase(GetData()->Data, str.ToCStr());
- }
-
- // Accesses raw bytes
- const char& operator [] (int index) const
- {
- OVR_ASSERT(index >= 0 && (UPInt)index < GetSize());
- return GetData()->Data[index];
- }
- const char& operator [] (UPInt index) const
- {
- OVR_ASSERT(index < GetSize());
- return GetData()->Data[index];
- }
-
-
- // Case insensitive keys are used to look up insensitive string in hash tables
- // for SWF files with version before SWF 7.
- struct NoCaseKey
- {
- const String* pStr;
- NoCaseKey(const String &str) : pStr(&str){};
- };
-
- bool operator == (const NoCaseKey& strKey) const
- {
- return (CompareNoCase(ToCStr(), strKey.pStr->ToCStr()) == 0);
- }
- bool operator != (const NoCaseKey& strKey) const
- {
- return !(CompareNoCase(ToCStr(), strKey.pStr->ToCStr()) == 0);
- }
-
- // Hash functor used for strings.
- struct HashFunctor
- {
- UPInt operator()(const String& data) const
- {
- UPInt size = data.GetSize();
- return String::BernsteinHashFunction((const char*)data, size);
- }
- };
- // Case-insensitive hash functor used for strings. Supports additional
- // lookup based on NoCaseKey.
- struct NoCaseHashFunctor
- {
- UPInt operator()(const String& data) const
- {
- UPInt size = data.GetSize();
- return String::BernsteinHashFunctionCIS((const char*)data, size);
- }
- UPInt operator()(const NoCaseKey& data) const
- {
- UPInt size = data.pStr->GetSize();
- return String::BernsteinHashFunctionCIS((const char*)data.pStr->ToCStr(), size);
- }
- };
-
-};
-
-
-//-----------------------------------------------------------------------------------
-// ***** String Buffer used for Building Strings
-
-class StringBuffer
-{
- char* pData;
- UPInt Size;
- UPInt BufferSize;
- UPInt GrowSize;
- mutable bool LengthIsSize;
-
-public:
-
- // Constructors / Destructor.
- StringBuffer();
- explicit StringBuffer(UPInt growSize);
- StringBuffer(const char* data);
- StringBuffer(const char* data, UPInt buflen);
- StringBuffer(const String& src);
- StringBuffer(const StringBuffer& src);
- explicit StringBuffer(const wchar_t* data);
- ~StringBuffer();
-
-
- // Modify grow size used for growing/shrinking the buffer.
- UPInt GetGrowSize() const { return GrowSize; }
- void SetGrowSize(UPInt growSize);
-
-
- // *** General Functions
- // Does not release memory, just sets Size to 0
- void Clear();
-
- // For casting to a pointer to char.
- operator const char*() const { return (pData) ? pData : ""; }
- // Pointer to raw buffer.
- const char* ToCStr() const { return (pData) ? pData : ""; }
-
- // Returns number of bytes.
- UPInt GetSize() const { return Size ; }
- // Tells whether or not the string is empty.
- bool IsEmpty() const { return GetSize() == 0; }
-
- // Returns number of characters
- UPInt GetLength() const;
-
- // Returns character at the specified index
- UInt32 GetCharAt(UPInt index) const;
- UInt32 GetFirstCharAt(UPInt index, const char** offset) const;
- UInt32 GetNextChar(const char** offset) const;
-
-
- // Resize the string to the new size
- void Resize(UPInt _size);
- void Reserve(UPInt _size);
-
- // Appends a character
- void AppendChar(UInt32 ch);
-
- // Append a string
- void AppendString(const wchar_t* pstr, SPInt len = -1);
- void AppendString(const char* putf8str, SPInt utf8StrSz = -1);
- void AppendFormat(const char* format, ...);
-
- // Assigned a string with dynamic data (copied through initializer).
- //void AssignString(const InitStruct& src, UPInt size);
-
- // Inserts substr at posAt
- void Insert (const char* substr, UPInt posAt, SPInt len = -1);
- // Inserts character at posAt
- UPInt InsertCharAt(UInt32 c, UPInt posAt);
-
- // Assignment
- void operator = (const char* str);
- void operator = (const wchar_t* str);
- void operator = (const String& src);
-
- // Addition
- void operator += (const String& src) { AppendString(src.ToCStr(),src.GetSize()); }
- void operator += (const char* psrc) { AppendString(psrc); }
- void operator += (const wchar_t* psrc) { AppendString(psrc); }
- void operator += (char ch) { AppendChar(ch); }
- //String operator + (const char* str) const ;
- //String operator + (const String& src) const ;
-
- // Accesses raw bytes
- char& operator [] (int index)
- {
- OVR_ASSERT(((UPInt)index) < GetSize());
- return pData[index];
- }
- char& operator [] (UPInt index)
- {
- OVR_ASSERT(index < GetSize());
- return pData[index];
- }
-
- const char& operator [] (int index) const
- {
- OVR_ASSERT(((UPInt)index) < GetSize());
- return pData[index];
- }
- const char& operator [] (UPInt index) const
- {
- OVR_ASSERT(index < GetSize());
- return pData[index];
- }
-};
-
-
-//
-// Wrapper for string data. The data must have a guaranteed
-// lifespan throughout the usage of the wrapper. Not intended for
-// cached usage. Not thread safe.
-//
-class StringDataPtr
-{
-public:
- StringDataPtr() : pStr(NULL), Size(0) {}
- StringDataPtr(const StringDataPtr& p)
- : pStr(p.pStr), Size(p.Size) {}
- StringDataPtr(const char* pstr, UPInt sz)
- : pStr(pstr), Size(sz) {}
- StringDataPtr(const char* pstr)
- : pStr(pstr), Size((pstr != NULL) ? OVR_strlen(pstr) : 0) {}
- explicit StringDataPtr(const String& str)
- : pStr(str.ToCStr()), Size(str.GetSize()) {}
- template <typename T, int N>
- StringDataPtr(const T (&v)[N])
- : pStr(v), Size(N) {}
-
-public:
- const char* ToCStr() const { return pStr; }
- UPInt GetSize() const { return Size; }
- bool IsEmpty() const { return GetSize() == 0; }
-
- // value is a prefix of this string
- // Character's values are not compared.
- bool IsPrefix(const StringDataPtr& value) const
- {
- return ToCStr() == value.ToCStr() && GetSize() >= value.GetSize();
- }
- // value is a suffix of this string
- // Character's values are not compared.
- bool IsSuffix(const StringDataPtr& value) const
- {
- return ToCStr() <= value.ToCStr() && (End()) == (value.End());
- }
-
- // Find first character.
- // init_ind - initial index.
- SPInt FindChar(char c, UPInt init_ind = 0) const
- {
- for (UPInt i = init_ind; i < GetSize(); ++i)
- if (pStr[i] == c)
- return static_cast<SPInt>(i);
-
- return -1;
- }
-
- // Find last character.
- // init_ind - initial index.
- SPInt FindLastChar(char c, UPInt init_ind = ~0) const
- {
- if (init_ind == (UPInt)~0 || init_ind > GetSize())
- init_ind = GetSize();
- else
- ++init_ind;
-
- for (UPInt i = init_ind; i > 0; --i)
- if (pStr[i - 1] == c)
- return static_cast<SPInt>(i - 1);
-
- return -1;
- }
-
- // Create new object and trim size bytes from the left.
- StringDataPtr GetTrimLeft(UPInt size) const
- {
- // Limit trim size to the size of the string.
- size = Alg::PMin(GetSize(), size);
-
- return StringDataPtr(ToCStr() + size, GetSize() - size);
- }
- // Create new object and trim size bytes from the right.
- StringDataPtr GetTrimRight(UPInt size) const
- {
- // Limit trim to the size of the string.
- size = Alg::PMin(GetSize(), size);
-
- return StringDataPtr(ToCStr(), GetSize() - size);
- }
-
- // Create new object, which contains next token.
- // Useful for parsing.
- StringDataPtr GetNextToken(char separator = ':') const
- {
- UPInt cur_pos = 0;
- const char* cur_str = ToCStr();
-
- for (; cur_pos < GetSize() && cur_str[cur_pos]; ++cur_pos)
- {
- if (cur_str[cur_pos] == separator)
- {
- break;
- }
- }
-
- return StringDataPtr(ToCStr(), cur_pos);
- }
-
- // Trim size bytes from the left.
- StringDataPtr& TrimLeft(UPInt size)
- {
- // Limit trim size to the size of the string.
- size = Alg::PMin(GetSize(), size);
- pStr += size;
- Size -= size;
-
- return *this;
- }
- // Trim size bytes from the right.
- StringDataPtr& TrimRight(UPInt size)
- {
- // Limit trim to the size of the string.
- size = Alg::PMin(GetSize(), size);
- Size -= size;
-
- return *this;
- }
-
- const char* Begin() const { return ToCStr(); }
- const char* End() const { return ToCStr() + GetSize(); }
-
- // Hash functor used string data pointers
- struct HashFunctor
- {
- UPInt operator()(const StringDataPtr& data) const
- {
- return String::BernsteinHashFunction(data.ToCStr(), data.GetSize());
- }
- };
-
- bool operator== (const StringDataPtr& data) const
- {
- return (OVR_strncmp(pStr, data.pStr, data.Size) == 0);
- }
-
-protected:
- const char* pStr;
- UPInt Size;
-};
-
-} // OVR
-
-#endif
+/************************************************************************************
+
+PublicHeader: OVR.h
+Filename : OVR_String.h
+Content : String UTF8 string implementation with copy-on-write semantics
+ (thread-safe for assignment but not modification).
+Created : September 19, 2012
+Notes :
+
+Copyright : Copyright 2012 Oculus VR, Inc. All Rights reserved.
+
+Use of this software is subject to the terms of the Oculus license
+agreement provided at the time of installation or download, or which
+otherwise accompanies this software in either electronic or hard copy form.
+
+************************************************************************************/
+
+#ifndef OVR_String_h
+#define OVR_String_h
+
+#include "OVR_Types.h"
+#include "OVR_Allocator.h"
+#include "OVR_UTF8Util.h"
+#include "OVR_Atomic.h"
+#include "OVR_Std.h"
+#include "OVR_Alg.h"
+
+namespace OVR {
+
+// ***** Classes
+
+class String;
+class StringBuffer;
+
+
+//-----------------------------------------------------------------------------------
+// ***** String Class
+
+// String is UTF8 based string class with copy-on-write implementation
+// for assignment.
+
+class String
+{
+protected:
+
+ enum FlagConstants
+ {
+ //Flag_GetLength = 0x7FFFFFFF,
+ // This flag is set if GetLength() == GetSize() for a string.
+ // Avoid extra scanning is Substring and indexing logic.
+ Flag_LengthIsSizeShift = (sizeof(UPInt)*8 - 1)
+ };
+
+
+ // Internal structure to hold string data
+ struct DataDesc
+ {
+ // Number of bytes. Will be the same as the number of chars if the characters
+ // are ascii, may not be equal to number of chars in case string data is UTF8.
+ UPInt Size;
+ volatile SInt32 RefCount;
+ char Data[1];
+
+ void AddRef()
+ {
+ AtomicOps<SInt32>::ExchangeAdd_NoSync(&RefCount, 1);
+ }
+ // Decrement ref count. This needs to be thread-safe, since
+ // a different thread could have also decremented the ref count.
+ // For example, if u start off with a ref count = 2. Now if u
+ // decrement the ref count and check against 0 in different
+ // statements, a different thread can also decrement the ref count
+ // in between our decrement and checking against 0 and will find
+ // the ref count = 0 and delete the object. This will lead to a crash
+ // when context switches to our thread and we'll be trying to delete
+ // an already deleted object. Hence decrementing the ref count and
+ // checking against 0 needs to made an atomic operation.
+ void Release()
+ {
+ if ((AtomicOps<SInt32>::ExchangeAdd_NoSync(&RefCount, -1) - 1) == 0)
+ OVR_FREE(this);
+ }
+
+ static UPInt GetLengthFlagBit() { return UPInt(1) << Flag_LengthIsSizeShift; }
+ UPInt GetSize() const { return Size & ~GetLengthFlagBit() ; }
+ UPInt GetLengthFlag() const { return Size & GetLengthFlagBit(); }
+ bool LengthIsSize() const { return GetLengthFlag() != 0; }
+ };
+
+ // Heap type of the string is encoded in the lower bits.
+ enum HeapType
+ {
+ HT_Global = 0, // Heap is global.
+ HT_Local = 1, // SF::String_loc: Heap is determined based on string's address.
+ HT_Dynamic = 2, // SF::String_temp: Heap is stored as a part of the class.
+ HT_Mask = 3
+ };
+
+ union {
+ DataDesc* pData;
+ UPInt HeapTypeBits;
+ };
+ typedef union {
+ DataDesc* pData;
+ UPInt HeapTypeBits;
+ } DataDescUnion;
+
+ inline HeapType GetHeapType() const { return (HeapType) (HeapTypeBits & HT_Mask); }
+
+ inline DataDesc* GetData() const
+ {
+ DataDescUnion u;
+ u.pData = pData;
+ u.HeapTypeBits = (u.HeapTypeBits & ~(UPInt)HT_Mask);
+ return u.pData;
+ }
+
+ inline void SetData(DataDesc* pdesc)
+ {
+ HeapType ht = GetHeapType();
+ pData = pdesc;
+ OVR_ASSERT((HeapTypeBits & HT_Mask) == 0);
+ HeapTypeBits |= ht;
+ }
+
+
+ DataDesc* AllocData(UPInt size, UPInt lengthIsSize);
+ DataDesc* AllocDataCopy1(UPInt size, UPInt lengthIsSize,
+ const char* pdata, UPInt copySize);
+ DataDesc* AllocDataCopy2(UPInt size, UPInt lengthIsSize,
+ const char* pdata1, UPInt copySize1,
+ const char* pdata2, UPInt copySize2);
+
+ // Special constructor to avoid data initalization when used in derived class.
+ struct NoConstructor { };
+ String(const NoConstructor&) { }
+
+public:
+
+ // For initializing string with dynamic buffer
+ struct InitStruct
+ {
+ virtual ~InitStruct() { }
+ virtual void InitString(char* pbuffer, UPInt size) const = 0;
+ };
+
+
+ // Constructors / Destructors.
+ String();
+ String(const char* data);
+ String(const char* data1, const char* pdata2, const char* pdata3 = 0);
+ String(const char* data, UPInt buflen);
+ String(const String& src);
+ String(const StringBuffer& src);
+ String(const InitStruct& src, UPInt size);
+ explicit String(const wchar_t* data);
+
+ // Destructor (Captain Obvious guarantees!)
+ ~String()
+ {
+ GetData()->Release();
+ }
+
+ // Declaration of NullString
+ static DataDesc NullData;
+
+
+ // *** General Functions
+
+ void Clear();
+
+ // For casting to a pointer to char.
+ operator const char*() const { return GetData()->Data; }
+ // Pointer to raw buffer.
+ const char* ToCStr() const { return GetData()->Data; }
+
+ // Returns number of bytes
+ UPInt GetSize() const { return GetData()->GetSize() ; }
+ // Tells whether or not the string is empty
+ bool IsEmpty() const { return GetSize() == 0; }
+
+ // Returns number of characters
+ UPInt GetLength() const;
+
+ // Returns character at the specified index
+ UInt32 GetCharAt(UPInt index) const;
+ UInt32 GetFirstCharAt(UPInt index, const char** offset) const;
+ UInt32 GetNextChar(const char** offset) const;
+
+ // Appends a character
+ void AppendChar(UInt32 ch);
+
+ // Append a string
+ void AppendString(const wchar_t* pstr, SPInt len = -1);
+ void AppendString(const char* putf8str, SPInt utf8StrSz = -1);
+
+ // Assigned a string with dynamic data (copied through initializer).
+ void AssignString(const InitStruct& src, UPInt size);
+ // Assigns string with known size.
+ void AssignString(const char* putf8str, UPInt size);
+
+ // Resize the string to the new size
+// void Resize(UPInt _size);
+
+ // Removes the character at posAt
+ void Remove(UPInt posAt, SPInt len = 1);
+
+ // Returns a String that's a substring of this.
+ // -start is the index of the first UTF8 character you want to include.
+ // -end is the index one past the last UTF8 character you want to include.
+ String Substring(UPInt start, UPInt end) const;
+
+ // Case-conversion
+ String ToUpper() const;
+ String ToLower() const;
+
+ // Inserts substr at posAt
+ String& Insert (const char* substr, UPInt posAt, SPInt len = -1);
+
+ // Inserts character at posAt
+ UPInt InsertCharAt(UInt32 c, UPInt posAt);
+
+ // Inserts substr at posAt, which is an index of a character (not byte).
+ // Of size is specified, it is in bytes.
+// String& Insert(const UInt32* substr, UPInt posAt, SPInt size = -1);
+
+ // Get Byte index of the character at position = index
+ UPInt GetByteIndex(UPInt index) const { return (UPInt)UTF8Util::GetByteIndex(index, GetData()->Data); }
+
+ // Utility: case-insensitive string compare. stricmp() & strnicmp() are not
+ // ANSI or POSIX, do not seem to appear in Linux.
+ static int OVR_STDCALL CompareNoCase(const char* a, const char* b);
+ static int OVR_STDCALL CompareNoCase(const char* a, const char* b, SPInt len);
+
+ // Hash function, case-insensitive
+ static UPInt OVR_STDCALL BernsteinHashFunctionCIS(const void* pdataIn, UPInt size, UPInt seed = 5381);
+
+ // Hash function, case-sensitive
+ static UPInt OVR_STDCALL BernsteinHashFunction(const void* pdataIn, UPInt size, UPInt seed = 5381);
+
+
+ // ***** File path parsing helper functions.
+ // Implemented in OVR_String_FilePath.cpp.
+
+ // Absolute paths can star with:
+ // - protocols: 'file://', 'http://'
+ // - windows drive: 'c:\'
+ // - UNC share name: '\\share'
+ // - unix root '/'
+ static bool HasAbsolutePath(const char* path);
+ static bool HasExtension(const char* path);
+ static bool HasProtocol(const char* path);
+
+ bool HasAbsolutePath() const { return HasAbsolutePath(ToCStr()); }
+ bool HasExtension() const { return HasExtension(ToCStr()); }
+ bool HasProtocol() const { return HasProtocol(ToCStr()); }
+
+ String GetProtocol() const; // Returns protocol, if any, with trailing '://'.
+ String GetPath() const; // Returns path with trailing '/'.
+ String GetFilename() const; // Returns filename, including extension.
+ String GetExtension() const; // Returns extension with a dot.
+
+ void StripProtocol(); // Strips front protocol, if any, from the string.
+ void StripExtension(); // Strips off trailing extension.
+
+
+ // Operators
+ // Assignment
+ void operator = (const char* str);
+ void operator = (const wchar_t* str);
+ void operator = (const String& src);
+ void operator = (const StringBuffer& src);
+
+ // Addition
+ void operator += (const String& src);
+ void operator += (const char* psrc) { AppendString(psrc); }
+ void operator += (const wchar_t* psrc) { AppendString(psrc); }
+ void operator += (char ch) { AppendChar(ch); }
+ String operator + (const char* str) const;
+ String operator + (const String& src) const;
+
+ // Comparison
+ bool operator == (const String& str) const
+ {
+ return (OVR_strcmp(GetData()->Data, str.GetData()->Data)== 0);
+ }
+
+ bool operator != (const String& str) const
+ {
+ return !operator == (str);
+ }
+
+ bool operator == (const char* str) const
+ {
+ return OVR_strcmp(GetData()->Data, str) == 0;
+ }
+
+ bool operator != (const char* str) const
+ {
+ return !operator == (str);
+ }
+
+ bool operator < (const char* pstr) const
+ {
+ return OVR_strcmp(GetData()->Data, pstr) < 0;
+ }
+
+ bool operator < (const String& str) const
+ {
+ return *this < str.GetData()->Data;
+ }
+
+ bool operator > (const char* pstr) const
+ {
+ return OVR_strcmp(GetData()->Data, pstr) > 0;
+ }
+
+ bool operator > (const String& str) const
+ {
+ return *this > str.GetData()->Data;
+ }
+
+ int CompareNoCase(const char* pstr) const
+ {
+ return CompareNoCase(GetData()->Data, pstr);
+ }
+ int CompareNoCase(const String& str) const
+ {
+ return CompareNoCase(GetData()->Data, str.ToCStr());
+ }
+
+ // Accesses raw bytes
+ const char& operator [] (int index) const
+ {
+ OVR_ASSERT(index >= 0 && (UPInt)index < GetSize());
+ return GetData()->Data[index];
+ }
+ const char& operator [] (UPInt index) const
+ {
+ OVR_ASSERT(index < GetSize());
+ return GetData()->Data[index];
+ }
+
+
+ // Case insensitive keys are used to look up insensitive string in hash tables
+ // for SWF files with version before SWF 7.
+ struct NoCaseKey
+ {
+ const String* pStr;
+ NoCaseKey(const String &str) : pStr(&str){};
+ };
+
+ bool operator == (const NoCaseKey& strKey) const
+ {
+ return (CompareNoCase(ToCStr(), strKey.pStr->ToCStr()) == 0);
+ }
+ bool operator != (const NoCaseKey& strKey) const
+ {
+ return !(CompareNoCase(ToCStr(), strKey.pStr->ToCStr()) == 0);
+ }
+
+ // Hash functor used for strings.
+ struct HashFunctor
+ {
+ UPInt operator()(const String& data) const
+ {
+ UPInt size = data.GetSize();
+ return String::BernsteinHashFunction((const char*)data, size);
+ }
+ };
+ // Case-insensitive hash functor used for strings. Supports additional
+ // lookup based on NoCaseKey.
+ struct NoCaseHashFunctor
+ {
+ UPInt operator()(const String& data) const
+ {
+ UPInt size = data.GetSize();
+ return String::BernsteinHashFunctionCIS((const char*)data, size);
+ }
+ UPInt operator()(const NoCaseKey& data) const
+ {
+ UPInt size = data.pStr->GetSize();
+ return String::BernsteinHashFunctionCIS((const char*)data.pStr->ToCStr(), size);
+ }
+ };
+
+};
+
+
+//-----------------------------------------------------------------------------------
+// ***** String Buffer used for Building Strings
+
+class StringBuffer
+{
+ char* pData;
+ UPInt Size;
+ UPInt BufferSize;
+ UPInt GrowSize;
+ mutable bool LengthIsSize;
+
+public:
+
+ // Constructors / Destructor.
+ StringBuffer();
+ explicit StringBuffer(UPInt growSize);
+ StringBuffer(const char* data);
+ StringBuffer(const char* data, UPInt buflen);
+ StringBuffer(const String& src);
+ StringBuffer(const StringBuffer& src);
+ explicit StringBuffer(const wchar_t* data);
+ ~StringBuffer();
+
+
+ // Modify grow size used for growing/shrinking the buffer.
+ UPInt GetGrowSize() const { return GrowSize; }
+ void SetGrowSize(UPInt growSize);
+
+
+ // *** General Functions
+ // Does not release memory, just sets Size to 0
+ void Clear();
+
+ // For casting to a pointer to char.
+ operator const char*() const { return (pData) ? pData : ""; }
+ // Pointer to raw buffer.
+ const char* ToCStr() const { return (pData) ? pData : ""; }
+
+ // Returns number of bytes.
+ UPInt GetSize() const { return Size ; }
+ // Tells whether or not the string is empty.
+ bool IsEmpty() const { return GetSize() == 0; }
+
+ // Returns number of characters
+ UPInt GetLength() const;
+
+ // Returns character at the specified index
+ UInt32 GetCharAt(UPInt index) const;
+ UInt32 GetFirstCharAt(UPInt index, const char** offset) const;
+ UInt32 GetNextChar(const char** offset) const;
+
+
+ // Resize the string to the new size
+ void Resize(UPInt _size);
+ void Reserve(UPInt _size);
+
+ // Appends a character
+ void AppendChar(UInt32 ch);
+
+ // Append a string
+ void AppendString(const wchar_t* pstr, SPInt len = -1);
+ void AppendString(const char* putf8str, SPInt utf8StrSz = -1);
+ void AppendFormat(const char* format, ...);
+
+ // Assigned a string with dynamic data (copied through initializer).
+ //void AssignString(const InitStruct& src, UPInt size);
+
+ // Inserts substr at posAt
+ void Insert (const char* substr, UPInt posAt, SPInt len = -1);
+ // Inserts character at posAt
+ UPInt InsertCharAt(UInt32 c, UPInt posAt);
+
+ // Assignment
+ void operator = (const char* str);
+ void operator = (const wchar_t* str);
+ void operator = (const String& src);
+
+ // Addition
+ void operator += (const String& src) { AppendString(src.ToCStr(),src.GetSize()); }
+ void operator += (const char* psrc) { AppendString(psrc); }
+ void operator += (const wchar_t* psrc) { AppendString(psrc); }
+ void operator += (char ch) { AppendChar(ch); }
+ //String operator + (const char* str) const ;
+ //String operator + (const String& src) const ;
+
+ // Accesses raw bytes
+ char& operator [] (int index)
+ {
+ OVR_ASSERT(((UPInt)index) < GetSize());
+ return pData[index];
+ }
+ char& operator [] (UPInt index)
+ {
+ OVR_ASSERT(index < GetSize());
+ return pData[index];
+ }
+
+ const char& operator [] (int index) const
+ {
+ OVR_ASSERT(((UPInt)index) < GetSize());
+ return pData[index];
+ }
+ const char& operator [] (UPInt index) const
+ {
+ OVR_ASSERT(index < GetSize());
+ return pData[index];
+ }
+};
+
+
+//
+// Wrapper for string data. The data must have a guaranteed
+// lifespan throughout the usage of the wrapper. Not intended for
+// cached usage. Not thread safe.
+//
+class StringDataPtr
+{
+public:
+ StringDataPtr() : pStr(NULL), Size(0) {}
+ StringDataPtr(const StringDataPtr& p)
+ : pStr(p.pStr), Size(p.Size) {}
+ StringDataPtr(const char* pstr, UPInt sz)
+ : pStr(pstr), Size(sz) {}
+ StringDataPtr(const char* pstr)
+ : pStr(pstr), Size((pstr != NULL) ? OVR_strlen(pstr) : 0) {}
+ explicit StringDataPtr(const String& str)
+ : pStr(str.ToCStr()), Size(str.GetSize()) {}
+ template <typename T, int N>
+ StringDataPtr(const T (&v)[N])
+ : pStr(v), Size(N) {}
+
+public:
+ const char* ToCStr() const { return pStr; }
+ UPInt GetSize() const { return Size; }
+ bool IsEmpty() const { return GetSize() == 0; }
+
+ // value is a prefix of this string
+ // Character's values are not compared.
+ bool IsPrefix(const StringDataPtr& value) const
+ {
+ return ToCStr() == value.ToCStr() && GetSize() >= value.GetSize();
+ }
+ // value is a suffix of this string
+ // Character's values are not compared.
+ bool IsSuffix(const StringDataPtr& value) const
+ {
+ return ToCStr() <= value.ToCStr() && (End()) == (value.End());
+ }
+
+ // Find first character.
+ // init_ind - initial index.
+ SPInt FindChar(char c, UPInt init_ind = 0) const
+ {
+ for (UPInt i = init_ind; i < GetSize(); ++i)
+ if (pStr[i] == c)
+ return static_cast<SPInt>(i);
+
+ return -1;
+ }
+
+ // Find last character.
+ // init_ind - initial index.
+ SPInt FindLastChar(char c, UPInt init_ind = ~0) const
+ {
+ if (init_ind == (UPInt)~0 || init_ind > GetSize())
+ init_ind = GetSize();
+ else
+ ++init_ind;
+
+ for (UPInt i = init_ind; i > 0; --i)
+ if (pStr[i - 1] == c)
+ return static_cast<SPInt>(i - 1);
+
+ return -1;
+ }
+
+ // Create new object and trim size bytes from the left.
+ StringDataPtr GetTrimLeft(UPInt size) const
+ {
+ // Limit trim size to the size of the string.
+ size = Alg::PMin(GetSize(), size);
+
+ return StringDataPtr(ToCStr() + size, GetSize() - size);
+ }
+ // Create new object and trim size bytes from the right.
+ StringDataPtr GetTrimRight(UPInt size) const
+ {
+ // Limit trim to the size of the string.
+ size = Alg::PMin(GetSize(), size);
+
+ return StringDataPtr(ToCStr(), GetSize() - size);
+ }
+
+ // Create new object, which contains next token.
+ // Useful for parsing.
+ StringDataPtr GetNextToken(char separator = ':') const
+ {
+ UPInt cur_pos = 0;
+ const char* cur_str = ToCStr();
+
+ for (; cur_pos < GetSize() && cur_str[cur_pos]; ++cur_pos)
+ {
+ if (cur_str[cur_pos] == separator)
+ {
+ break;
+ }
+ }
+
+ return StringDataPtr(ToCStr(), cur_pos);
+ }
+
+ // Trim size bytes from the left.
+ StringDataPtr& TrimLeft(UPInt size)
+ {
+ // Limit trim size to the size of the string.
+ size = Alg::PMin(GetSize(), size);
+ pStr += size;
+ Size -= size;
+
+ return *this;
+ }
+ // Trim size bytes from the right.
+ StringDataPtr& TrimRight(UPInt size)
+ {
+ // Limit trim to the size of the string.
+ size = Alg::PMin(GetSize(), size);
+ Size -= size;
+
+ return *this;
+ }
+
+ const char* Begin() const { return ToCStr(); }
+ const char* End() const { return ToCStr() + GetSize(); }
+
+ // Hash functor used string data pointers
+ struct HashFunctor
+ {
+ UPInt operator()(const StringDataPtr& data) const
+ {
+ return String::BernsteinHashFunction(data.ToCStr(), data.GetSize());
+ }
+ };
+
+ bool operator== (const StringDataPtr& data) const
+ {
+ return (OVR_strncmp(pStr, data.pStr, data.Size) == 0);
+ }
+
+protected:
+ const char* pStr;
+ UPInt Size;
+};
+
+} // OVR
+
+#endif
diff --git a/LibOVR/Src/Kernel/OVR_StringHash.h b/LibOVR/Src/Kernel/OVR_StringHash.h
index 237dc7e..ae8010c 100644
--- a/LibOVR/Src/Kernel/OVR_StringHash.h
+++ b/LibOVR/Src/Kernel/OVR_StringHash.h
@@ -1,89 +1,89 @@
-/************************************************************************************
-
-PublicHeader: None
-Filename : OVR_StringHash.h
-Content : String hash table used when optional case-insensitive
- lookup is required.
-Created : September 19, 2012
-Notes :
-
-Copyright : Copyright 2012 Oculus VR, Inc. All Rights reserved.
-
-Use of this software is subject to the terms of the Oculus license
-agreement provided at the time of installation or download, or which
-otherwise accompanies this software in either electronic or hard copy form.
-
-************************************************************************************/
-
-#ifndef OVR_StringHash_h
-#define OVR_StringHash_h
-
-#include "OVR_String.h"
-#include "OVR_Hash.h"
-
-namespace OVR {
-
-//-----------------------------------------------------------------------------------
-// *** StringHash
-
-// This is a custom string hash table that supports case-insensitive
-// searches through special functions such as GetCaseInsensitive, etc.
-// This class is used for Flash labels, exports and other case-insensitive tables.
-
-template<class U, class Allocator = ContainerAllocator<U> >
-class StringHash : public Hash<String, U, String::NoCaseHashFunctor, Allocator>
-{
-public:
- typedef U ValueType;
- typedef StringHash<U, Allocator> SelfType;
- typedef Hash<String, U, String::NoCaseHashFunctor, Allocator> BaseType;
-
-public:
-
- void operator = (const SelfType& src) { BaseType::operator = (src); }
-
- bool GetCaseInsensitive(const String& key, U* pvalue) const
- {
- String::NoCaseKey ikey(key);
- return BaseType::GetAlt(ikey, pvalue);
- }
- // Pointer-returning get variety.
- const U* GetCaseInsensitive(const String& key) const
- {
- String::NoCaseKey ikey(key);
- return BaseType::GetAlt(ikey);
- }
- U* GetCaseInsensitive(const String& key)
- {
- String::NoCaseKey ikey(key);
- return BaseType::GetAlt(ikey);
- }
-
-
- typedef typename BaseType::Iterator base_iterator;
-
- base_iterator FindCaseInsensitive(const String& key)
- {
- String::NoCaseKey ikey(key);
- return BaseType::FindAlt(ikey);
- }
-
- // Set just uses a find and assigns value if found. The key is not modified;
- // this behavior is identical to Flash string variable assignment.
- void SetCaseInsensitive(const String& key, const U& value)
- {
- base_iterator it = FindCaseInsensitive(key);
- if (it != BaseType::End())
- {
- it->Second = value;
- }
- else
- {
- BaseType::Add(key, value);
- }
- }
-};
-
-} // OVR
-
-#endif
+/************************************************************************************
+
+PublicHeader: None
+Filename : OVR_StringHash.h
+Content : String hash table used when optional case-insensitive
+ lookup is required.
+Created : September 19, 2012
+Notes :
+
+Copyright : Copyright 2012 Oculus VR, Inc. All Rights reserved.
+
+Use of this software is subject to the terms of the Oculus license
+agreement provided at the time of installation or download, or which
+otherwise accompanies this software in either electronic or hard copy form.
+
+************************************************************************************/
+
+#ifndef OVR_StringHash_h
+#define OVR_StringHash_h
+
+#include "OVR_String.h"
+#include "OVR_Hash.h"
+
+namespace OVR {
+
+//-----------------------------------------------------------------------------------
+// *** StringHash
+
+// This is a custom string hash table that supports case-insensitive
+// searches through special functions such as GetCaseInsensitive, etc.
+// This class is used for Flash labels, exports and other case-insensitive tables.
+
+template<class U, class Allocator = ContainerAllocator<U> >
+class StringHash : public Hash<String, U, String::NoCaseHashFunctor, Allocator>
+{
+public:
+ typedef U ValueType;
+ typedef StringHash<U, Allocator> SelfType;
+ typedef Hash<String, U, String::NoCaseHashFunctor, Allocator> BaseType;
+
+public:
+
+ void operator = (const SelfType& src) { BaseType::operator = (src); }
+
+ bool GetCaseInsensitive(const String& key, U* pvalue) const
+ {
+ String::NoCaseKey ikey(key);
+ return BaseType::GetAlt(ikey, pvalue);
+ }
+ // Pointer-returning get variety.
+ const U* GetCaseInsensitive(const String& key) const
+ {
+ String::NoCaseKey ikey(key);
+ return BaseType::GetAlt(ikey);
+ }
+ U* GetCaseInsensitive(const String& key)
+ {
+ String::NoCaseKey ikey(key);
+ return BaseType::GetAlt(ikey);
+ }
+
+
+ typedef typename BaseType::Iterator base_iterator;
+
+ base_iterator FindCaseInsensitive(const String& key)
+ {
+ String::NoCaseKey ikey(key);
+ return BaseType::FindAlt(ikey);
+ }
+
+ // Set just uses a find and assigns value if found. The key is not modified;
+ // this behavior is identical to Flash string variable assignment.
+ void SetCaseInsensitive(const String& key, const U& value)
+ {
+ base_iterator it = FindCaseInsensitive(key);
+ if (it != BaseType::End())
+ {
+ it->Second = value;
+ }
+ else
+ {
+ BaseType::Add(key, value);
+ }
+ }
+};
+
+} // OVR
+
+#endif
diff --git a/LibOVR/Src/Kernel/OVR_String_FormatUtil.cpp b/LibOVR/Src/Kernel/OVR_String_FormatUtil.cpp
index a6ceb3a..72e7f7f 100644
--- a/LibOVR/Src/Kernel/OVR_String_FormatUtil.cpp
+++ b/LibOVR/Src/Kernel/OVR_String_FormatUtil.cpp
@@ -1,42 +1,42 @@
-/************************************************************************************
-
-Filename : OVR_String_FormatUtil.cpp
-Content : String format functions.
-Created : February 27, 2013
-Notes :
-
-Copyright : Copyright 2013 Oculus VR, Inc. All Rights reserved.
-
-Use of this software is subject to the terms of the Oculus license
-agreement provided at the time of installation or download, or which
-otherwise accompanies this software in either electronic or hard copy form.
-
-************************************************************************************/
-
-#include "OVR_String.h"
-#include "OVR_Log.h"
-
-namespace OVR {
-
-void StringBuffer::AppendFormat(const char* format, ...)
-{
- va_list argList;
-
- va_start(argList, format);
- UPInt size = OVR_vscprintf(format, argList);
- va_end(argList);
-
- char* buffer = (char*) OVR_ALLOC(sizeof(char) * (size+1));
-
- va_start(argList, format);
- UPInt result = OVR_vsprintf(buffer, size+1, format, argList);
- OVR_UNUSED1(result);
- va_end(argList);
- OVR_ASSERT_LOG(result == size, ("Error in OVR_vsprintf"));
-
- AppendString(buffer);
-
- OVR_FREE(buffer);
-}
-
-} // OVR
+/************************************************************************************
+
+Filename : OVR_String_FormatUtil.cpp
+Content : String format functions.
+Created : February 27, 2013
+Notes :
+
+Copyright : Copyright 2013 Oculus VR, Inc. All Rights reserved.
+
+Use of this software is subject to the terms of the Oculus license
+agreement provided at the time of installation or download, or which
+otherwise accompanies this software in either electronic or hard copy form.
+
+************************************************************************************/
+
+#include "OVR_String.h"
+#include "OVR_Log.h"
+
+namespace OVR {
+
+void StringBuffer::AppendFormat(const char* format, ...)
+{
+ va_list argList;
+
+ va_start(argList, format);
+ UPInt size = OVR_vscprintf(format, argList);
+ va_end(argList);
+
+ char* buffer = (char*) OVR_ALLOC(sizeof(char) * (size+1));
+
+ va_start(argList, format);
+ UPInt result = OVR_vsprintf(buffer, size+1, format, argList);
+ OVR_UNUSED1(result);
+ va_end(argList);
+ OVR_ASSERT_LOG(result == size, ("Error in OVR_vsprintf"));
+
+ AppendString(buffer);
+
+ OVR_FREE(buffer);
+}
+
+} // OVR
diff --git a/LibOVR/Src/Kernel/OVR_String_PathUtil.cpp b/LibOVR/Src/Kernel/OVR_String_PathUtil.cpp
index 27e79c6..698d16e 100644
--- a/LibOVR/Src/Kernel/OVR_String_PathUtil.cpp
+++ b/LibOVR/Src/Kernel/OVR_String_PathUtil.cpp
@@ -1,200 +1,200 @@
-/************************************************************************************
-
-Filename : OVR_String_PathUtil.cpp
-Content : String filename/url helper function
-Created : September 19, 2012
-Notes :
-
-Copyright : Copyright 2012 Oculus VR, Inc. All Rights reserved.
-
-Use of this software is subject to the terms of the Oculus license
-agreement provided at the time of installation or download, or which
-otherwise accompanies this software in either electronic or hard copy form.
-
-************************************************************************************/
-
-#include "OVR_String.h"
-#include "OVR_UTF8Util.h"
-
-namespace OVR {
-
-//--------------------------------------------------------------------
-// ***** Path-Scanner helper function
-
-// Scans file path finding filename start and extension start, fills in their addess.
-void ScanFilePath(const char* url, const char** pfilename, const char** pext)
-{
- const char* urlStart = url;
- const char *filename = 0;
- const char *lastDot = 0;
-
- UInt32 charVal = UTF8Util::DecodeNextChar(&url);
-
- while (charVal != 0)
- {
- if ((charVal == '/') || (charVal == '\\'))
- {
- filename = url;
- lastDot = 0;
- }
- else if (charVal == '.')
- {
- lastDot = url - 1;
- }
-
- charVal = UTF8Util::DecodeNextChar(&url);
- }
-
- if (pfilename)
- {
- // It was a naked filename
- if (urlStart && (*urlStart != '.') && *urlStart)
- *pfilename = urlStart;
- else
- *pfilename = filename;
- }
-
- if (pext)
- {
- *pext = lastDot;
- }
-}
-
-// Scans till the end of protocol. Returns first character past protocol,
-// 0 if not found.
-// - protocol: 'file://', 'http://'
-const char* ScanPathProtocol(const char* url)
-{
- UInt32 charVal = UTF8Util::DecodeNextChar(&url);
- UInt32 charVal2;
-
- while (charVal != 0)
- {
- // Treat a colon followed by a slash as absolute.
- if (charVal == ':')
- {
- charVal2 = UTF8Util::DecodeNextChar(&url);
- charVal = UTF8Util::DecodeNextChar(&url);
- if ((charVal == '/') && (charVal2 == '\\'))
- return url;
- }
- charVal = UTF8Util::DecodeNextChar(&url);
- }
- return 0;
-}
-
-
-//--------------------------------------------------------------------
-// ***** String Path API implementation
-
-bool String::HasAbsolutePath(const char* url)
-{
- // Absolute paths can star with:
- // - protocols: 'file://', 'http://'
- // - windows drive: 'c:\'
- // - UNC share name: '\\share'
- // - unix root '/'
-
- // On the other hand, relative paths are:
- // - directory: 'directory/file'
- // - this directory: './file'
- // - parent directory: '../file'
- //
- // For now, we don't parse '.' or '..' out, but instead let it be concatenated
- // to string and let the OS figure it out. This, however, is not good for file
- // name matching in library/etc, so it should be improved.
-
- if (!url || !*url)
- return true; // Treat empty strings as absolute.
-
- UInt32 charVal = UTF8Util::DecodeNextChar(&url);
-
- // Fist character of '/' or '\\' means absolute url.
- if ((charVal == '/') || (charVal == '\\'))
- return true;
-
- while (charVal != 0)
- {
- // Treat a colon followed by a slash as absolute.
- if (charVal == ':')
- {
- charVal = UTF8Util::DecodeNextChar(&url);
- // Protocol or windows drive. Absolute.
- if ((charVal == '/') || (charVal == '\\'))
- return true;
- }
- else if ((charVal == '/') || (charVal == '\\'))
- {
- // Not a first character (else 'if' above the loop would have caught it).
- // Must be a relative url.
- break;
- }
-
- charVal = UTF8Util::DecodeNextChar(&url);
- }
-
- // We get here for relative paths.
- return false;
-}
-
-
-bool String::HasExtension(const char* path)
-{
- const char* ext = 0;
- ScanFilePath(path, 0, &ext);
- return ext != 0;
-}
-bool String::HasProtocol(const char* path)
-{
- return ScanPathProtocol(path) != 0;
-}
-
-
-String String::GetPath() const
-{
- const char* filename = 0;
- ScanFilePath(ToCStr(), &filename, 0);
-
- // Technically we can have extra logic somewhere for paths,
- // such as enforcing protocol and '/' only based on flags,
- // but we keep it simple for now.
- return String(ToCStr(), filename ? (filename-ToCStr()) : GetSize());
-}
-
-String String::GetProtocol() const
-{
- const char* protocolEnd = ScanPathProtocol(ToCStr());
- return String(ToCStr(), protocolEnd ? (protocolEnd-ToCStr()) : 0);
-}
-
-String String::GetFilename() const
-{
- const char* filename = 0;
- ScanFilePath(ToCStr(), &filename, 0);
- return String(filename);
-}
-String String::GetExtension() const
-{
- const char* ext = 0;
- ScanFilePath(ToCStr(), 0, &ext);
- return String(ext);
-}
-
-void String::StripExtension()
-{
- const char* ext = 0;
- ScanFilePath(ToCStr(), 0, &ext);
- if (ext)
- {
- *this = String(ToCStr(), ext-ToCStr());
- }
-}
-
-void String::StripProtocol()
-{
- const char* protocol = ScanPathProtocol(ToCStr());
- if (protocol)
- AssignString(protocol, OVR_strlen(protocol));
-}
-
-} // OVR
+/************************************************************************************
+
+Filename : OVR_String_PathUtil.cpp
+Content : String filename/url helper function
+Created : September 19, 2012
+Notes :
+
+Copyright : Copyright 2012 Oculus VR, Inc. All Rights reserved.
+
+Use of this software is subject to the terms of the Oculus license
+agreement provided at the time of installation or download, or which
+otherwise accompanies this software in either electronic or hard copy form.
+
+************************************************************************************/
+
+#include "OVR_String.h"
+#include "OVR_UTF8Util.h"
+
+namespace OVR {
+
+//--------------------------------------------------------------------
+// ***** Path-Scanner helper function
+
+// Scans file path finding filename start and extension start, fills in their addess.
+void ScanFilePath(const char* url, const char** pfilename, const char** pext)
+{
+ const char* urlStart = url;
+ const char *filename = 0;
+ const char *lastDot = 0;
+
+ UInt32 charVal = UTF8Util::DecodeNextChar(&url);
+
+ while (charVal != 0)
+ {
+ if ((charVal == '/') || (charVal == '\\'))
+ {
+ filename = url;
+ lastDot = 0;
+ }
+ else if (charVal == '.')
+ {
+ lastDot = url - 1;
+ }
+
+ charVal = UTF8Util::DecodeNextChar(&url);
+ }
+
+ if (pfilename)
+ {
+ // It was a naked filename
+ if (urlStart && (*urlStart != '.') && *urlStart)
+ *pfilename = urlStart;
+ else
+ *pfilename = filename;
+ }
+
+ if (pext)
+ {
+ *pext = lastDot;
+ }
+}
+
+// Scans till the end of protocol. Returns first character past protocol,
+// 0 if not found.
+// - protocol: 'file://', 'http://'
+const char* ScanPathProtocol(const char* url)
+{
+ UInt32 charVal = UTF8Util::DecodeNextChar(&url);
+ UInt32 charVal2;
+
+ while (charVal != 0)
+ {
+ // Treat a colon followed by a slash as absolute.
+ if (charVal == ':')
+ {
+ charVal2 = UTF8Util::DecodeNextChar(&url);
+ charVal = UTF8Util::DecodeNextChar(&url);
+ if ((charVal == '/') && (charVal2 == '\\'))
+ return url;
+ }
+ charVal = UTF8Util::DecodeNextChar(&url);
+ }
+ return 0;
+}
+
+
+//--------------------------------------------------------------------
+// ***** String Path API implementation
+
+bool String::HasAbsolutePath(const char* url)
+{
+ // Absolute paths can star with:
+ // - protocols: 'file://', 'http://'
+ // - windows drive: 'c:\'
+ // - UNC share name: '\\share'
+ // - unix root '/'
+
+ // On the other hand, relative paths are:
+ // - directory: 'directory/file'
+ // - this directory: './file'
+ // - parent directory: '../file'
+ //
+ // For now, we don't parse '.' or '..' out, but instead let it be concatenated
+ // to string and let the OS figure it out. This, however, is not good for file
+ // name matching in library/etc, so it should be improved.
+
+ if (!url || !*url)
+ return true; // Treat empty strings as absolute.
+
+ UInt32 charVal = UTF8Util::DecodeNextChar(&url);
+
+ // Fist character of '/' or '\\' means absolute url.
+ if ((charVal == '/') || (charVal == '\\'))
+ return true;
+
+ while (charVal != 0)
+ {
+ // Treat a colon followed by a slash as absolute.
+ if (charVal == ':')
+ {
+ charVal = UTF8Util::DecodeNextChar(&url);
+ // Protocol or windows drive. Absolute.
+ if ((charVal == '/') || (charVal == '\\'))
+ return true;
+ }
+ else if ((charVal == '/') || (charVal == '\\'))
+ {
+ // Not a first character (else 'if' above the loop would have caught it).
+ // Must be a relative url.
+ break;
+ }
+
+ charVal = UTF8Util::DecodeNextChar(&url);
+ }
+
+ // We get here for relative paths.
+ return false;
+}
+
+
+bool String::HasExtension(const char* path)
+{
+ const char* ext = 0;
+ ScanFilePath(path, 0, &ext);
+ return ext != 0;
+}
+bool String::HasProtocol(const char* path)
+{
+ return ScanPathProtocol(path) != 0;
+}
+
+
+String String::GetPath() const
+{
+ const char* filename = 0;
+ ScanFilePath(ToCStr(), &filename, 0);
+
+ // Technically we can have extra logic somewhere for paths,
+ // such as enforcing protocol and '/' only based on flags,
+ // but we keep it simple for now.
+ return String(ToCStr(), filename ? (filename-ToCStr()) : GetSize());
+}
+
+String String::GetProtocol() const
+{
+ const char* protocolEnd = ScanPathProtocol(ToCStr());
+ return String(ToCStr(), protocolEnd ? (protocolEnd-ToCStr()) : 0);
+}
+
+String String::GetFilename() const
+{
+ const char* filename = 0;
+ ScanFilePath(ToCStr(), &filename, 0);
+ return String(filename);
+}
+String String::GetExtension() const
+{
+ const char* ext = 0;
+ ScanFilePath(ToCStr(), 0, &ext);
+ return String(ext);
+}
+
+void String::StripExtension()
+{
+ const char* ext = 0;
+ ScanFilePath(ToCStr(), 0, &ext);
+ if (ext)
+ {
+ *this = String(ToCStr(), ext-ToCStr());
+ }
+}
+
+void String::StripProtocol()
+{
+ const char* protocol = ScanPathProtocol(ToCStr());
+ if (protocol)
+ AssignString(protocol, OVR_strlen(protocol));
+}
+
+} // OVR
diff --git a/LibOVR/Src/Kernel/OVR_SysFile.cpp b/LibOVR/Src/Kernel/OVR_SysFile.cpp
index f72a8d2..13f0e75 100644
--- a/LibOVR/Src/Kernel/OVR_SysFile.cpp
+++ b/LibOVR/Src/Kernel/OVR_SysFile.cpp
@@ -1,125 +1,125 @@
-/**************************************************************************
-
-Filename : OVR_SysFile.cpp
-Content : File wrapper class implementation (Win32)
-
-Created : April 5, 1999
-Authors : Michael Antonov
-
-Copyright : Copyright 2011 Oculus VR, Inc. All Rights reserved.
-
-Use of this software is subject to the terms of the Oculus license
-agreement provided at the time of installation or download, or which
-otherwise accompanies this software in either electronic or hard copy form.
-
-**************************************************************************/
-
-#define GFILE_CXX
-
-// Standard C library (Captain Obvious guarantees!)
-#include <stdio.h>
-
-#include "OVR_SysFile.h"
-
-namespace OVR {
-
-// This is - a dummy file that fails on all calls.
-
-class UnopenedFile : public File
-{
-public:
- UnopenedFile() { }
- ~UnopenedFile() { }
-
- virtual const char* GetFilePath() { return 0; }
-
- // ** File Information
- virtual bool IsValid() { return 0; }
- virtual bool IsWritable() { return 0; }
-
- // Return position / file size
- virtual int Tell() { return 0; }
- virtual SInt64 LTell() { return 0; }
- virtual int GetLength() { return 0; }
- virtual SInt64 LGetLength() { return 0; }
-
-// virtual bool Stat(FileStats *pfs) { return 0; }
- virtual int GetErrorCode() { return Error_FileNotFound; }
-
- // ** Stream implementation & I/O
- virtual int Write(const UByte *pbuffer, int numBytes) { return -1; OVR_UNUSED2(pbuffer, numBytes); }
- virtual int Read(UByte *pbuffer, int numBytes) { return -1; OVR_UNUSED2(pbuffer, numBytes); }
- virtual int SkipBytes(int numBytes) { return 0; OVR_UNUSED(numBytes); }
- virtual int BytesAvailable() { return 0; }
- virtual bool Flush() { return 0; }
- virtual int Seek(int offset, int origin) { return -1; OVR_UNUSED2(offset, origin); }
- virtual SInt64 LSeek(SInt64 offset, int origin) { return -1; OVR_UNUSED2(offset, origin); }
-
- virtual int CopyFromStream(File *pstream, int byteSize) { return -1; OVR_UNUSED2(pstream, byteSize); }
- virtual bool Close() { return 0; }
-};
-
-
-
-// ***** System File
-
-// System file is created to access objects on file system directly
-// This file can refer directly to path
-
-// ** Constructor
-SysFile::SysFile() : DelegatedFile(0)
-{
- pFile = *new UnopenedFile;
-}
-
-File* FileFILEOpen(const String& path, int flags, int mode);
-
-// Opens a file
-SysFile::SysFile(const String& path, int flags, int mode) : DelegatedFile(0)
-{
- Open(path, flags, mode);
-}
-
-
-// ** Open & management
-// Will fail if file's already open
-bool SysFile::Open(const String& path, int flags, int mode)
-{
- pFile = *FileFILEOpen(path, flags, mode);
- if ((!pFile) || (!pFile->IsValid()))
- {
- pFile = *new UnopenedFile;
- return 0;
- }
- //pFile = *OVR_NEW DelegatedFile(pFile); // MA Testing
- if (flags & Open_Buffered)
- pFile = *new BufferedFile(pFile);
- return 1;
-}
-
-
-// ** Overrides
-
-int SysFile::GetErrorCode()
-{
- return pFile ? pFile->GetErrorCode() : Error_FileNotFound;
-}
-
-
-// Overrides to provide re-open support
-bool SysFile::IsValid()
-{
- return pFile && pFile->IsValid();
-}
-bool SysFile::Close()
-{
- if (IsValid())
- {
- DelegatedFile::Close();
- pFile = *new UnopenedFile;
- return 1;
- }
- return 0;
-}
-
-} // OVR
+/**************************************************************************
+
+Filename : OVR_SysFile.cpp
+Content : File wrapper class implementation (Win32)
+
+Created : April 5, 1999
+Authors : Michael Antonov
+
+Copyright : Copyright 2011 Oculus VR, Inc. All Rights reserved.
+
+Use of this software is subject to the terms of the Oculus license
+agreement provided at the time of installation or download, or which
+otherwise accompanies this software in either electronic or hard copy form.
+
+**************************************************************************/
+
+#define GFILE_CXX
+
+// Standard C library (Captain Obvious guarantees!)
+#include <stdio.h>
+
+#include "OVR_SysFile.h"
+
+namespace OVR {
+
+// This is - a dummy file that fails on all calls.
+
+class UnopenedFile : public File
+{
+public:
+ UnopenedFile() { }
+ ~UnopenedFile() { }
+
+ virtual const char* GetFilePath() { return 0; }
+
+ // ** File Information
+ virtual bool IsValid() { return 0; }
+ virtual bool IsWritable() { return 0; }
+
+ // Return position / file size
+ virtual int Tell() { return 0; }
+ virtual SInt64 LTell() { return 0; }
+ virtual int GetLength() { return 0; }
+ virtual SInt64 LGetLength() { return 0; }
+
+// virtual bool Stat(FileStats *pfs) { return 0; }
+ virtual int GetErrorCode() { return Error_FileNotFound; }
+
+ // ** Stream implementation & I/O
+ virtual int Write(const UByte *pbuffer, int numBytes) { return -1; OVR_UNUSED2(pbuffer, numBytes); }
+ virtual int Read(UByte *pbuffer, int numBytes) { return -1; OVR_UNUSED2(pbuffer, numBytes); }
+ virtual int SkipBytes(int numBytes) { return 0; OVR_UNUSED(numBytes); }
+ virtual int BytesAvailable() { return 0; }
+ virtual bool Flush() { return 0; }
+ virtual int Seek(int offset, int origin) { return -1; OVR_UNUSED2(offset, origin); }
+ virtual SInt64 LSeek(SInt64 offset, int origin) { return -1; OVR_UNUSED2(offset, origin); }
+
+ virtual int CopyFromStream(File *pstream, int byteSize) { return -1; OVR_UNUSED2(pstream, byteSize); }
+ virtual bool Close() { return 0; }
+};
+
+
+
+// ***** System File
+
+// System file is created to access objects on file system directly
+// This file can refer directly to path
+
+// ** Constructor
+SysFile::SysFile() : DelegatedFile(0)
+{
+ pFile = *new UnopenedFile;
+}
+
+File* FileFILEOpen(const String& path, int flags, int mode);
+
+// Opens a file
+SysFile::SysFile(const String& path, int flags, int mode) : DelegatedFile(0)
+{
+ Open(path, flags, mode);
+}
+
+
+// ** Open & management
+// Will fail if file's already open
+bool SysFile::Open(const String& path, int flags, int mode)
+{
+ pFile = *FileFILEOpen(path, flags, mode);
+ if ((!pFile) || (!pFile->IsValid()))
+ {
+ pFile = *new UnopenedFile;
+ return 0;
+ }
+ //pFile = *OVR_NEW DelegatedFile(pFile); // MA Testing
+ if (flags & Open_Buffered)
+ pFile = *new BufferedFile(pFile);
+ return 1;
+}
+
+
+// ** Overrides
+
+int SysFile::GetErrorCode()
+{
+ return pFile ? pFile->GetErrorCode() : Error_FileNotFound;
+}
+
+
+// Overrides to provide re-open support
+bool SysFile::IsValid()
+{
+ return pFile && pFile->IsValid();
+}
+bool SysFile::Close()
+{
+ if (IsValid())
+ {
+ DelegatedFile::Close();
+ pFile = *new UnopenedFile;
+ return 1;
+ }
+ return 0;
+}
+
+} // OVR
diff --git a/LibOVR/Src/Kernel/OVR_SysFile.h b/LibOVR/Src/Kernel/OVR_SysFile.h
index a9bb0a0..d078df1 100644
--- a/LibOVR/Src/Kernel/OVR_SysFile.h
+++ b/LibOVR/Src/Kernel/OVR_SysFile.h
@@ -1,93 +1,93 @@
-/************************************************************************************
-
-PublicHeader: Kernel
-Filename : OVR_SysFile.h
-Content : Header for all internal file management - functions and structures
- to be inherited by OS specific subclasses.
-Created : September 19, 2012
-Notes :
-
-Notes : errno may not be preserved across use of GBaseFile member functions
- : Directories cannot be deleted while files opened from them are in use
- (For the GetFullName function)
-
-Copyright : Copyright 2012 Oculus VR, Inc. All Rights reserved.
-
-Use of this software is subject to the terms of the Oculus license
-agreement provided at the time of installation or download, or which
-otherwise accompanies this software in either electronic or hard copy form.
-
-************************************************************************************/
-
-#ifndef OVR_SysFile_h
-#define OVR_SysFile_h
-
-#include "OVR_File.h"
-
-namespace OVR {
-
-// ***** Declared classes
-class SysFile;
-
-//-----------------------------------------------------------------------------------
-// *** File Statistics
-
-// This class contents are similar to _stat, providing
-// creation, modify and other information about the file.
-struct FileStat
-{
- // No change or create time because they are not available on most systems
- SInt64 ModifyTime;
- SInt64 AccessTime;
- SInt64 FileSize;
-
- bool operator== (const FileStat& stat) const
- {
- return ( (ModifyTime == stat.ModifyTime) &&
- (AccessTime == stat.AccessTime) &&
- (FileSize == stat.FileSize) );
- }
-};
-
-//-----------------------------------------------------------------------------------
-// *** System File
-
-// System file is created to access objects on file system directly
-// This file can refer directly to path.
-// System file can be open & closed several times; however, such use is not recommended
-// This class is realy a wrapper around an implementation of File interface for a
-// particular platform.
-
-class SysFile : public DelegatedFile
-{
-protected:
- SysFile(const SysFile &source) : DelegatedFile () { OVR_UNUSED(source); }
-public:
-
- // ** Constructor
- SysFile();
- // Opens a file
- SysFile(const String& path, int flags = Open_Read|Open_Buffered, int mode = Mode_ReadWrite);
-
- // ** Open & management
- bool Open(const String& path, int flags = Open_Read|Open_Buffered, int mode = Mode_ReadWrite);
-
- OVR_FORCE_INLINE bool Create(const String& path, int mode = Mode_ReadWrite)
- { return Open(path, Open_ReadWrite|Open_Create, mode); }
-
- // Helper function: obtain file statistics information. In GFx, this is used to detect file changes.
- // Return 0 if function failed, most likely because the file doesn't exist.
- static bool OVR_CDECL GetFileStat(FileStat* pfileStats, const String& path);
-
- // ** Overrides
- // Overridden to provide re-open support
- virtual int GetErrorCode();
-
- virtual bool IsValid();
-
- virtual bool Close();
-};
-
-} // Scaleform
-
-#endif
+/************************************************************************************
+
+PublicHeader: Kernel
+Filename : OVR_SysFile.h
+Content : Header for all internal file management - functions and structures
+ to be inherited by OS specific subclasses.
+Created : September 19, 2012
+Notes :
+
+Notes : errno may not be preserved across use of GBaseFile member functions
+ : Directories cannot be deleted while files opened from them are in use
+ (For the GetFullName function)
+
+Copyright : Copyright 2012 Oculus VR, Inc. All Rights reserved.
+
+Use of this software is subject to the terms of the Oculus license
+agreement provided at the time of installation or download, or which
+otherwise accompanies this software in either electronic or hard copy form.
+
+************************************************************************************/
+
+#ifndef OVR_SysFile_h
+#define OVR_SysFile_h
+
+#include "OVR_File.h"
+
+namespace OVR {
+
+// ***** Declared classes
+class SysFile;
+
+//-----------------------------------------------------------------------------------
+// *** File Statistics
+
+// This class contents are similar to _stat, providing
+// creation, modify and other information about the file.
+struct FileStat
+{
+ // No change or create time because they are not available on most systems
+ SInt64 ModifyTime;
+ SInt64 AccessTime;
+ SInt64 FileSize;
+
+ bool operator== (const FileStat& stat) const
+ {
+ return ( (ModifyTime == stat.ModifyTime) &&
+ (AccessTime == stat.AccessTime) &&
+ (FileSize == stat.FileSize) );
+ }
+};
+
+//-----------------------------------------------------------------------------------
+// *** System File
+
+// System file is created to access objects on file system directly
+// This file can refer directly to path.
+// System file can be open & closed several times; however, such use is not recommended
+// This class is realy a wrapper around an implementation of File interface for a
+// particular platform.
+
+class SysFile : public DelegatedFile
+{
+protected:
+ SysFile(const SysFile &source) : DelegatedFile () { OVR_UNUSED(source); }
+public:
+
+ // ** Constructor
+ SysFile();
+ // Opens a file
+ SysFile(const String& path, int flags = Open_Read|Open_Buffered, int mode = Mode_ReadWrite);
+
+ // ** Open & management
+ bool Open(const String& path, int flags = Open_Read|Open_Buffered, int mode = Mode_ReadWrite);
+
+ OVR_FORCE_INLINE bool Create(const String& path, int mode = Mode_ReadWrite)
+ { return Open(path, Open_ReadWrite|Open_Create, mode); }
+
+ // Helper function: obtain file statistics information. In GFx, this is used to detect file changes.
+ // Return 0 if function failed, most likely because the file doesn't exist.
+ static bool OVR_CDECL GetFileStat(FileStat* pfileStats, const String& path);
+
+ // ** Overrides
+ // Overridden to provide re-open support
+ virtual int GetErrorCode();
+
+ virtual bool IsValid();
+
+ virtual bool Close();
+};
+
+} // Scaleform
+
+#endif
diff --git a/LibOVR/Src/Kernel/OVR_System.cpp b/LibOVR/Src/Kernel/OVR_System.cpp
index 8eba8e2..410bfe1 100644
--- a/LibOVR/Src/Kernel/OVR_System.cpp
+++ b/LibOVR/Src/Kernel/OVR_System.cpp
@@ -1,70 +1,70 @@
-/************************************************************************************
-
-Filename : OVR_System.cpp
-Content : General kernel initialization/cleanup, including that
- of the memory allocator.
-Created : September 19, 2012
-Notes :
-
-Copyright : Copyright 2012 Oculus VR, Inc. All Rights reserved.
-
-Use of this software is subject to the terms of the Oculus license
-agreement provided at the time of installation or download, or which
-otherwise accompanies this software in either electronic or hard copy form.
-
-************************************************************************************/
-
-#include "OVR_System.h"
-#include "OVR_Threads.h"
-#include "OVR_Timer.h"
-
-namespace OVR {
-
-// ***** OVR::System Implementation
-
-// Initializes System core, installing allocator.
-void System::Init(Log* log, Allocator *palloc)
-{
- if (!Allocator::GetInstance())
- {
- Log::SetGlobalLog(log);
- Timer::initializeTimerSystem();
- Allocator::setInstance(palloc);
- }
- else
- {
- OVR_DEBUG_LOG(("System::Init failed - duplicate call."));
- }
-}
-
-void System::Destroy()
-{
- if (Allocator::GetInstance())
- {
- // Wait for all threads to finish; this must be done so that memory
- // allocator and all destructors finalize correctly.
-#ifdef OVR_ENABLE_THREADS
- Thread::FinishAllThreads();
-#endif
-
- // Shutdown heap and destroy SysAlloc singleton, if any.
- Allocator::GetInstance()->onSystemShutdown();
- Allocator::setInstance(0);
-
- Timer::shutdownTimerSystem();
- Log::SetGlobalLog(Log::GetDefaultLog());
- }
- else
- {
- OVR_DEBUG_LOG(("System::Destroy failed - System not initialized."));
- }
-}
-
-// Returns 'true' if system was properly initialized.
-bool System::IsInitialized()
-{
- return Allocator::GetInstance() != 0;
-}
-
-} // OVR
-
+/************************************************************************************
+
+Filename : OVR_System.cpp
+Content : General kernel initialization/cleanup, including that
+ of the memory allocator.
+Created : September 19, 2012
+Notes :
+
+Copyright : Copyright 2012 Oculus VR, Inc. All Rights reserved.
+
+Use of this software is subject to the terms of the Oculus license
+agreement provided at the time of installation or download, or which
+otherwise accompanies this software in either electronic or hard copy form.
+
+************************************************************************************/
+
+#include "OVR_System.h"
+#include "OVR_Threads.h"
+#include "OVR_Timer.h"
+
+namespace OVR {
+
+// ***** OVR::System Implementation
+
+// Initializes System core, installing allocator.
+void System::Init(Log* log, Allocator *palloc)
+{
+ if (!Allocator::GetInstance())
+ {
+ Log::SetGlobalLog(log);
+ Timer::initializeTimerSystem();
+ Allocator::setInstance(palloc);
+ }
+ else
+ {
+ OVR_DEBUG_LOG(("System::Init failed - duplicate call."));
+ }
+}
+
+void System::Destroy()
+{
+ if (Allocator::GetInstance())
+ {
+ // Wait for all threads to finish; this must be done so that memory
+ // allocator and all destructors finalize correctly.
+#ifdef OVR_ENABLE_THREADS
+ Thread::FinishAllThreads();
+#endif
+
+ // Shutdown heap and destroy SysAlloc singleton, if any.
+ Allocator::GetInstance()->onSystemShutdown();
+ Allocator::setInstance(0);
+
+ Timer::shutdownTimerSystem();
+ Log::SetGlobalLog(Log::GetDefaultLog());
+ }
+ else
+ {
+ OVR_DEBUG_LOG(("System::Destroy failed - System not initialized."));
+ }
+}
+
+// Returns 'true' if system was properly initialized.
+bool System::IsInitialized()
+{
+ return Allocator::GetInstance() != 0;
+}
+
+} // OVR
+
diff --git a/LibOVR/Src/Kernel/OVR_System.h b/LibOVR/Src/Kernel/OVR_System.h
index e53b4c8..10d9b2d 100644
--- a/LibOVR/Src/Kernel/OVR_System.h
+++ b/LibOVR/Src/Kernel/OVR_System.h
@@ -1,67 +1,67 @@
-/************************************************************************************
-
-PublicHeader: OVR
-Filename : OVR_System.h
-Content : General kernel initialization/cleanup, including that
- of the memory allocator.
-Created : September 19, 2012
-Notes :
-
-Copyright : Copyright 2012 Oculus VR, Inc. All Rights reserved.
-
-Use of this software is subject to the terms of the Oculus license
-agreement provided at the time of installation or download, or which
-otherwise accompanies this software in either electronic or hard copy form.
-
-************************************************************************************/
-
-#ifndef OVR_System_h
-#define OVR_System_h
-
-#include "OVR_Allocator.h"
-#include "OVR_Log.h"
-
-namespace OVR {
-
-// ***** System Core Initialization class
-
-// System initialization must take place before any other OVR_Kernel objects are used;
-// this is done my calling System::Init(). Among other things, this is necessary to
-// initialize the memory allocator. Similarly, System::Destroy must be
-// called before program exist for proper cleanup. Both of these tasks can be achieved by
-// simply creating System object first, allowing its constructor/destructor do the work.
-
-// TBD: Require additional System class for Oculus Rift API?
-
-class System
-{
-public:
-
- // System constructor expects allocator to be specified, if it is being substituted.
- System(Log* log = Log::ConfigureDefaultLog(LogMask_Debug),
- Allocator* palloc = DefaultAllocator::InitSystemSingleton())
- {
- Init(log, palloc);
- }
-
- ~System()
- {
- Destroy();
- }
-
- // Returns 'true' if system was properly initialized.
- static bool OVR_CDECL IsInitialized();
-
- // Initializes System core. Users can override memory implementation by passing
- // a different Allocator here.
- static void OVR_CDECL Init(Log* log = Log::ConfigureDefaultLog(LogMask_Debug),
- Allocator *palloc = DefaultAllocator::InitSystemSingleton());
-
- // De-initializes System more, finalizing the threading system and destroying
- // the global memory allocator.
- static void OVR_CDECL Destroy();
-};
-
-} // OVR
-
-#endif
+/************************************************************************************
+
+PublicHeader: OVR
+Filename : OVR_System.h
+Content : General kernel initialization/cleanup, including that
+ of the memory allocator.
+Created : September 19, 2012
+Notes :
+
+Copyright : Copyright 2012 Oculus VR, Inc. All Rights reserved.
+
+Use of this software is subject to the terms of the Oculus license
+agreement provided at the time of installation or download, or which
+otherwise accompanies this software in either electronic or hard copy form.
+
+************************************************************************************/
+
+#ifndef OVR_System_h
+#define OVR_System_h
+
+#include "OVR_Allocator.h"
+#include "OVR_Log.h"
+
+namespace OVR {
+
+// ***** System Core Initialization class
+
+// System initialization must take place before any other OVR_Kernel objects are used;
+// this is done my calling System::Init(). Among other things, this is necessary to
+// initialize the memory allocator. Similarly, System::Destroy must be
+// called before program exist for proper cleanup. Both of these tasks can be achieved by
+// simply creating System object first, allowing its constructor/destructor do the work.
+
+// TBD: Require additional System class for Oculus Rift API?
+
+class System
+{
+public:
+
+ // System constructor expects allocator to be specified, if it is being substituted.
+ System(Log* log = Log::ConfigureDefaultLog(LogMask_Debug),
+ Allocator* palloc = DefaultAllocator::InitSystemSingleton())
+ {
+ Init(log, palloc);
+ }
+
+ ~System()
+ {
+ Destroy();
+ }
+
+ // Returns 'true' if system was properly initialized.
+ static bool OVR_CDECL IsInitialized();
+
+ // Initializes System core. Users can override memory implementation by passing
+ // a different Allocator here.
+ static void OVR_CDECL Init(Log* log = Log::ConfigureDefaultLog(LogMask_Debug),
+ Allocator *palloc = DefaultAllocator::InitSystemSingleton());
+
+ // De-initializes System more, finalizing the threading system and destroying
+ // the global memory allocator.
+ static void OVR_CDECL Destroy();
+};
+
+} // OVR
+
+#endif
diff --git a/LibOVR/Src/Kernel/OVR_Threads.h b/LibOVR/Src/Kernel/OVR_Threads.h
index 9c29fe0..747cba2 100644
--- a/LibOVR/Src/Kernel/OVR_Threads.h
+++ b/LibOVR/Src/Kernel/OVR_Threads.h
@@ -1,396 +1,396 @@
-/************************************************************************************
-
-PublicHeader: None
-Filename : OVR_Threads.h
-Content : Contains thread-related (safe) functionality
-Created : September 19, 2012
-Notes :
-
-Copyright : Copyright 2012 Oculus VR, Inc. All Rights reserved.
-
-Use of this software is subject to the terms of the Oculus license
-agreement provided at the time of installation or download, or which
-otherwise accompanies this software in either electronic or hard copy form.
-
-************************************************************************************/
-#ifndef OVR_Threads_h
-#define OVR_Threads_h
-
-#include "OVR_Types.h"
-#include "OVR_Atomic.h"
-#include "OVR_RefCount.h"
-#include "OVR_Array.h"
-
-// Defines the infinite wait delay timeout
-#define OVR_WAIT_INFINITE 0xFFFFFFFF
-
-// To be defined in the project configuration options
-#ifdef OVR_ENABLE_THREADS
-
-
-namespace OVR {
-
-//-----------------------------------------------------------------------------------
-// ****** Declared classes
-
-// Declared with thread support only
-class Mutex;
-class WaitCondition;
-class Event;
-// Implementation forward declarations
-class MutexImpl;
-class WaitConditionImpl;
-
-
-
-//-----------------------------------------------------------------------------------
-// ***** Mutex
-
-// Mutex class represents a system Mutex synchronization object that provides access
-// serialization between different threads, allowing one thread mutually exclusive access
-// to a resource. Mutex is more heavy-weight then Lock, but supports WaitCondition.
-
-class Mutex
-{
- friend class WaitConditionImpl;
- friend class MutexImpl;
-
- MutexImpl *pImpl;
-
-public:
- // Constructor/destructor
- Mutex(bool recursive = 1);
- ~Mutex();
-
- // Locking functions
- void DoLock();
- bool TryLock();
- void Unlock();
-
- // Returns 1 if the mutes is currently locked by another thread
- // Returns 0 if the mutex is not locked by another thread, and can therefore be acquired.
- bool IsLockedByAnotherThread();
-
- // Locker class; Used for automatic locking of a mutex withing scope
- class Locker
- {
- public:
- Mutex *pMutex;
- Locker(Mutex *pmutex)
- { pMutex = pmutex; pMutex->DoLock(); }
- ~Locker()
- { pMutex->Unlock(); }
- };
-};
-
-
-//-----------------------------------------------------------------------------------
-// ***** WaitCondition
-
-/*
- WaitCondition is a synchronization primitive that can be used to implement what is known as a monitor.
- Dependent threads wait on a wait condition by calling Wait(), and get woken up by other threads that
- call Notify() or NotifyAll().
-
- The unique feature of this class is that it provides an atomic way of first releasing a Mutex, and then
- starting a wait on a wait condition. If both the mutex and the wait condition are associated with the same
- resource, this ensures that any condition checked for while the mutex was locked does not change before
- the wait on the condition is actually initiated.
-*/
-
-class WaitCondition
-{
- friend class WaitConditionImpl;
- // Internal implementation structure
- WaitConditionImpl *pImpl;
-
-public:
- // Constructor/destructor
- WaitCondition();
- ~WaitCondition();
-
- // Release mutex and wait for condition. The mutex is re-aquired after the wait.
- // Delay is specified in milliseconds (1/1000 of a second).
- bool Wait(Mutex *pmutex, unsigned delay = OVR_WAIT_INFINITE);
-
- // Notify a condition, releasing at one object waiting
- void Notify();
- // Notify a condition, releasing all objects waiting
- void NotifyAll();
-};
-
-
-//-----------------------------------------------------------------------------------
-// ***** Event
-
-// Event is a wait-able synchronization object similar to Windows event.
-// Event can be waited on until it's signaled by another thread calling
-// either SetEvent or PulseEvent.
-
-class Event
-{
- // Event state, its mutex and the wait condition
- volatile bool State;
- volatile bool Temporary;
- mutable Mutex StateMutex;
- WaitCondition StateWaitCondition;
-
- void updateState(bool newState, bool newTemp, bool mustNotify);
-
-public:
- Event(bool setInitially = 0) : State(setInitially), Temporary(false) { }
- ~Event() { }
-
- // Wait on an event condition until it is set
- // Delay is specified in milliseconds (1/1000 of a second).
- bool Wait(unsigned delay = OVR_WAIT_INFINITE);
-
- // Set an event, releasing objects waiting on it
- void SetEvent()
- { updateState(true, false, true); }
-
- // Reset an event, un-signaling it
- void ResetEvent()
- { updateState(false, false, false); }
-
- // Set and then reset an event once a waiter is released.
- // If threads are already waiting, they will be notified and released
- // If threads are not waiting, the event is set until the first thread comes in
- void PulseEvent()
- { updateState(true, true, true); }
-};
-
-
-//-----------------------------------------------------------------------------------
-// ***** Thread class
-
-// ThreadId uniquely identifies a thread; returned by GetCurrentThreadId() and
-// Thread::GetThreadId.
-typedef void* ThreadId;
-
-
-// *** Thread flags
-
-// Indicates that the thread is has been started, i.e. Start method has been called, and threads
-// OnExit() method has not yet been called/returned.
-#define OVR_THREAD_STARTED 0x01
-// This flag is set once the thread has ran, and finished.
-#define OVR_THREAD_FINISHED 0x02
-// This flag is set temporarily if this thread was started suspended. It is used internally.
-#define OVR_THREAD_START_SUSPENDED 0x08
-// This flag is used to ask a thread to exit. Message driven threads will usually check this flag
-// and finish once it is set.
-#define OVR_THREAD_EXIT 0x10
-
-
-class Thread : public RefCountBase<Thread>
-{ // NOTE: Waitable must be the first base since it implements RefCountImpl.
-
-public:
-
- // *** Callback functions, can be used instead of overriding Run
-
- // Run function prototypes.
- // Thread function and user handle passed to it, executed by the default
- // Thread::Run implementation if not null.
- typedef int (*ThreadFn)(Thread *pthread, void* h);
-
- // Thread ThreadFunction1 is executed if not 0, otherwise ThreadFunction2 is tried
- ThreadFn ThreadFunction;
- // User handle passes to a thread
- void* UserHandle;
-
- // Thread state to start a thread with
- enum ThreadState
- {
- NotRunning = 0,
- Running = 1,
- Suspended = 2
- };
-
- // Thread priority
- enum ThreadPriority
- {
- CriticalPriority,
- HighestPriority,
- AboveNormalPriority,
- NormalPriority,
- BelowNormalPriority,
- LowestPriority,
- IdlePriority,
- };
-
- // Thread constructor parameters
- struct CreateParams
- {
- CreateParams(ThreadFn func = 0, void* hand = 0, UPInt ssize = 128 * 1024,
- int proc = -1, ThreadState state = NotRunning, ThreadPriority prior = NormalPriority)
- : threadFunction(func), userHandle(hand), stackSize(ssize),
- processor(proc), initialState(state), priority(prior) {}
- ThreadFn threadFunction; // Thread function
- void* userHandle; // User handle passes to a thread
- UPInt stackSize; // Thread stack size
- int processor; // Thread hardware processor
- ThreadState initialState; //
- ThreadPriority priority; // Thread priority
- };
-
- // *** Constructors
-
- // A default constructor always creates a thread in NotRunning state, because
- // the derived class has not yet been initialized. The derived class can call Start explicitly.
- // "processor" parameter specifies which hardware processor this thread will be run on.
- // -1 means OS decides this. Implemented only on Win32
- Thread(UPInt stackSize = 128 * 1024, int processor = -1);
- // Constructors that initialize the thread with a pointer to function.
- // An option to start a thread is available, but it should not be used if classes are derived from Thread.
- // "processor" parameter specifies which hardware processor this thread will be run on.
- // -1 means OS decides this. Implemented only on Win32
- Thread(ThreadFn threadFunction, void* userHandle = 0, UPInt stackSize = 128 * 1024,
- int processor = -1, ThreadState initialState = NotRunning);
- // Constructors that initialize the thread with a create parameters structure.
- explicit Thread(const CreateParams& params);
-
- // Destructor.
- virtual ~Thread();
-
- // Waits for all Threads to finish; should be called only from the root
- // application thread. Once this function returns, we know that all other
- // thread's references to Thread object have been released.
- static void OVR_CDECL FinishAllThreads();
-
-
- // *** Overridable Run function for thread processing
-
- // - returning from this method will end the execution of the thread
- // - return value is usually 0 for success
- virtual int Run();
- // Called after return/exit function
- virtual void OnExit();
-
-
- // *** Thread management
-
- // Starts the thread if its not already running
- // - internally sets up the threading and calls Run()
- // - initial state can either be Running or Suspended, NotRunning will just fail and do nothing
- // - returns the exit code
- virtual bool Start(ThreadState initialState = Running);
-
- // Quits with an exit code
- virtual void Exit(int exitCode=0);
-
- // Suspend the thread until resumed
- // Returns 1 for success, 0 for failure.
- bool Suspend();
- // Resumes currently suspended thread
- // Returns 1 for success, 0 for failure.
- bool Resume();
-
- // Static function to return a pointer to the current thread
- //static Thread* GetThread();
-
-
- // *** Thread status query functions
-
- bool GetExitFlag() const;
- void SetExitFlag(bool exitFlag);
-
- // Determines whether the thread was running and is now finished
- bool IsFinished() const;
- // Determines if the thread is currently suspended
- bool IsSuspended() const;
- // Returns current thread state
- ThreadState GetThreadState() const;
-
- // Returns the number of available CPUs on the system
- static int GetCPUCount();
-
- // Returns the thread exit code. Exit code is initialized to 0,
- // and set to the return value if Run function after the thread is finished.
- inline int GetExitCode() const { return ExitCode; }
- // Returns an OS handle
-#if defined(OVR_OS_WIN32)
- void* GetOSHandle() const { return ThreadHandle; }
-#else
- pthread_t GetOSHandle() const { return ThreadHandle; }
-#endif
-
-#if defined(OVR_OS_WIN32)
- ThreadId GetThreadId() const { return IdValue; }
-#else
- ThreadId GetThreadId() const { return (ThreadId)GetOSHandle(); }
-#endif
-
- static int GetOSPriority(ThreadPriority);
- // *** Sleep
-
- // Sleep secs seconds
- static bool Sleep(unsigned secs);
- // Sleep msecs milliseconds
- static bool MSleep(unsigned msecs);
-
-
- // *** Debugging functionality
-#if defined(OVR_OS_WIN32)
- virtual void SetThreadName( const char* name );
-#else
- virtual void SetThreadName( const char* name ) { OVR_UNUSED(name); }
-#endif
-
-private:
-#if defined(OVR_OS_WIN32)
- friend unsigned WINAPI Thread_Win32StartFn(void *pthread);
-
-#else
- friend void *Thread_PthreadStartFn(void * phandle);
-
- static int InitAttr;
- static pthread_attr_t Attr;
-#endif
-
-protected:
- // Thread state flags
- AtomicInt<UInt32> ThreadFlags;
- AtomicInt<SInt32> SuspendCount;
- UPInt StackSize;
-
- // Hardware processor which this thread is running on.
- int Processor;
- ThreadPriority Priority;
-
-#if defined(OVR_OS_WIN32)
- void* ThreadHandle;
- volatile ThreadId IdValue;
-
- // System-specific cleanup function called from destructor
- void CleanupSystemThread();
-
-#else
- pthread_t ThreadHandle;
-#endif
-
- // Exit code of the thread, as returned by Run.
- int ExitCode;
-
- // Internal run function.
- int PRun();
- // Finishes the thread and releases internal reference to it.
- void FinishAndRelease();
-
- void Init(const CreateParams& params);
-
- // Protected copy constructor
- Thread(const Thread &source) { OVR_UNUSED(source); }
-
-};
-
-// Returns the unique Id of a thread it is called on, intended for
-// comparison purposes.
-ThreadId GetCurrentThreadId();
-
-
-} // OVR
-
-#endif // OVR_ENABLE_THREADS
-#endif // OVR_Threads_h
+/************************************************************************************
+
+PublicHeader: None
+Filename : OVR_Threads.h
+Content : Contains thread-related (safe) functionality
+Created : September 19, 2012
+Notes :
+
+Copyright : Copyright 2012 Oculus VR, Inc. All Rights reserved.
+
+Use of this software is subject to the terms of the Oculus license
+agreement provided at the time of installation or download, or which
+otherwise accompanies this software in either electronic or hard copy form.
+
+************************************************************************************/
+#ifndef OVR_Threads_h
+#define OVR_Threads_h
+
+#include "OVR_Types.h"
+#include "OVR_Atomic.h"
+#include "OVR_RefCount.h"
+#include "OVR_Array.h"
+
+// Defines the infinite wait delay timeout
+#define OVR_WAIT_INFINITE 0xFFFFFFFF
+
+// To be defined in the project configuration options
+#ifdef OVR_ENABLE_THREADS
+
+
+namespace OVR {
+
+//-----------------------------------------------------------------------------------
+// ****** Declared classes
+
+// Declared with thread support only
+class Mutex;
+class WaitCondition;
+class Event;
+// Implementation forward declarations
+class MutexImpl;
+class WaitConditionImpl;
+
+
+
+//-----------------------------------------------------------------------------------
+// ***** Mutex
+
+// Mutex class represents a system Mutex synchronization object that provides access
+// serialization between different threads, allowing one thread mutually exclusive access
+// to a resource. Mutex is more heavy-weight then Lock, but supports WaitCondition.
+
+class Mutex
+{
+ friend class WaitConditionImpl;
+ friend class MutexImpl;
+
+ MutexImpl *pImpl;
+
+public:
+ // Constructor/destructor
+ Mutex(bool recursive = 1);
+ ~Mutex();
+
+ // Locking functions
+ void DoLock();
+ bool TryLock();
+ void Unlock();
+
+ // Returns 1 if the mutes is currently locked by another thread
+ // Returns 0 if the mutex is not locked by another thread, and can therefore be acquired.
+ bool IsLockedByAnotherThread();
+
+ // Locker class; Used for automatic locking of a mutex withing scope
+ class Locker
+ {
+ public:
+ Mutex *pMutex;
+ Locker(Mutex *pmutex)
+ { pMutex = pmutex; pMutex->DoLock(); }
+ ~Locker()
+ { pMutex->Unlock(); }
+ };
+};
+
+
+//-----------------------------------------------------------------------------------
+// ***** WaitCondition
+
+/*
+ WaitCondition is a synchronization primitive that can be used to implement what is known as a monitor.
+ Dependent threads wait on a wait condition by calling Wait(), and get woken up by other threads that
+ call Notify() or NotifyAll().
+
+ The unique feature of this class is that it provides an atomic way of first releasing a Mutex, and then
+ starting a wait on a wait condition. If both the mutex and the wait condition are associated with the same
+ resource, this ensures that any condition checked for while the mutex was locked does not change before
+ the wait on the condition is actually initiated.
+*/
+
+class WaitCondition
+{
+ friend class WaitConditionImpl;
+ // Internal implementation structure
+ WaitConditionImpl *pImpl;
+
+public:
+ // Constructor/destructor
+ WaitCondition();
+ ~WaitCondition();
+
+ // Release mutex and wait for condition. The mutex is re-aquired after the wait.
+ // Delay is specified in milliseconds (1/1000 of a second).
+ bool Wait(Mutex *pmutex, unsigned delay = OVR_WAIT_INFINITE);
+
+ // Notify a condition, releasing at one object waiting
+ void Notify();
+ // Notify a condition, releasing all objects waiting
+ void NotifyAll();
+};
+
+
+//-----------------------------------------------------------------------------------
+// ***** Event
+
+// Event is a wait-able synchronization object similar to Windows event.
+// Event can be waited on until it's signaled by another thread calling
+// either SetEvent or PulseEvent.
+
+class Event
+{
+ // Event state, its mutex and the wait condition
+ volatile bool State;
+ volatile bool Temporary;
+ mutable Mutex StateMutex;
+ WaitCondition StateWaitCondition;
+
+ void updateState(bool newState, bool newTemp, bool mustNotify);
+
+public:
+ Event(bool setInitially = 0) : State(setInitially), Temporary(false) { }
+ ~Event() { }
+
+ // Wait on an event condition until it is set
+ // Delay is specified in milliseconds (1/1000 of a second).
+ bool Wait(unsigned delay = OVR_WAIT_INFINITE);
+
+ // Set an event, releasing objects waiting on it
+ void SetEvent()
+ { updateState(true, false, true); }
+
+ // Reset an event, un-signaling it
+ void ResetEvent()
+ { updateState(false, false, false); }
+
+ // Set and then reset an event once a waiter is released.
+ // If threads are already waiting, they will be notified and released
+ // If threads are not waiting, the event is set until the first thread comes in
+ void PulseEvent()
+ { updateState(true, true, true); }
+};
+
+
+//-----------------------------------------------------------------------------------
+// ***** Thread class
+
+// ThreadId uniquely identifies a thread; returned by GetCurrentThreadId() and
+// Thread::GetThreadId.
+typedef void* ThreadId;
+
+
+// *** Thread flags
+
+// Indicates that the thread is has been started, i.e. Start method has been called, and threads
+// OnExit() method has not yet been called/returned.
+#define OVR_THREAD_STARTED 0x01
+// This flag is set once the thread has ran, and finished.
+#define OVR_THREAD_FINISHED 0x02
+// This flag is set temporarily if this thread was started suspended. It is used internally.
+#define OVR_THREAD_START_SUSPENDED 0x08
+// This flag is used to ask a thread to exit. Message driven threads will usually check this flag
+// and finish once it is set.
+#define OVR_THREAD_EXIT 0x10
+
+
+class Thread : public RefCountBase<Thread>
+{ // NOTE: Waitable must be the first base since it implements RefCountImpl.
+
+public:
+
+ // *** Callback functions, can be used instead of overriding Run
+
+ // Run function prototypes.
+ // Thread function and user handle passed to it, executed by the default
+ // Thread::Run implementation if not null.
+ typedef int (*ThreadFn)(Thread *pthread, void* h);
+
+ // Thread ThreadFunction1 is executed if not 0, otherwise ThreadFunction2 is tried
+ ThreadFn ThreadFunction;
+ // User handle passes to a thread
+ void* UserHandle;
+
+ // Thread state to start a thread with
+ enum ThreadState
+ {
+ NotRunning = 0,
+ Running = 1,
+ Suspended = 2
+ };
+
+ // Thread priority
+ enum ThreadPriority
+ {
+ CriticalPriority,
+ HighestPriority,
+ AboveNormalPriority,
+ NormalPriority,
+ BelowNormalPriority,
+ LowestPriority,
+ IdlePriority,
+ };
+
+ // Thread constructor parameters
+ struct CreateParams
+ {
+ CreateParams(ThreadFn func = 0, void* hand = 0, UPInt ssize = 128 * 1024,
+ int proc = -1, ThreadState state = NotRunning, ThreadPriority prior = NormalPriority)
+ : threadFunction(func), userHandle(hand), stackSize(ssize),
+ processor(proc), initialState(state), priority(prior) {}
+ ThreadFn threadFunction; // Thread function
+ void* userHandle; // User handle passes to a thread
+ UPInt stackSize; // Thread stack size
+ int processor; // Thread hardware processor
+ ThreadState initialState; //
+ ThreadPriority priority; // Thread priority
+ };
+
+ // *** Constructors
+
+ // A default constructor always creates a thread in NotRunning state, because
+ // the derived class has not yet been initialized. The derived class can call Start explicitly.
+ // "processor" parameter specifies which hardware processor this thread will be run on.
+ // -1 means OS decides this. Implemented only on Win32
+ Thread(UPInt stackSize = 128 * 1024, int processor = -1);
+ // Constructors that initialize the thread with a pointer to function.
+ // An option to start a thread is available, but it should not be used if classes are derived from Thread.
+ // "processor" parameter specifies which hardware processor this thread will be run on.
+ // -1 means OS decides this. Implemented only on Win32
+ Thread(ThreadFn threadFunction, void* userHandle = 0, UPInt stackSize = 128 * 1024,
+ int processor = -1, ThreadState initialState = NotRunning);
+ // Constructors that initialize the thread with a create parameters structure.
+ explicit Thread(const CreateParams& params);
+
+ // Destructor.
+ virtual ~Thread();
+
+ // Waits for all Threads to finish; should be called only from the root
+ // application thread. Once this function returns, we know that all other
+ // thread's references to Thread object have been released.
+ static void OVR_CDECL FinishAllThreads();
+
+
+ // *** Overridable Run function for thread processing
+
+ // - returning from this method will end the execution of the thread
+ // - return value is usually 0 for success
+ virtual int Run();
+ // Called after return/exit function
+ virtual void OnExit();
+
+
+ // *** Thread management
+
+ // Starts the thread if its not already running
+ // - internally sets up the threading and calls Run()
+ // - initial state can either be Running or Suspended, NotRunning will just fail and do nothing
+ // - returns the exit code
+ virtual bool Start(ThreadState initialState = Running);
+
+ // Quits with an exit code
+ virtual void Exit(int exitCode=0);
+
+ // Suspend the thread until resumed
+ // Returns 1 for success, 0 for failure.
+ bool Suspend();
+ // Resumes currently suspended thread
+ // Returns 1 for success, 0 for failure.
+ bool Resume();
+
+ // Static function to return a pointer to the current thread
+ //static Thread* GetThread();
+
+
+ // *** Thread status query functions
+
+ bool GetExitFlag() const;
+ void SetExitFlag(bool exitFlag);
+
+ // Determines whether the thread was running and is now finished
+ bool IsFinished() const;
+ // Determines if the thread is currently suspended
+ bool IsSuspended() const;
+ // Returns current thread state
+ ThreadState GetThreadState() const;
+
+ // Returns the number of available CPUs on the system
+ static int GetCPUCount();
+
+ // Returns the thread exit code. Exit code is initialized to 0,
+ // and set to the return value if Run function after the thread is finished.
+ inline int GetExitCode() const { return ExitCode; }
+ // Returns an OS handle
+#if defined(OVR_OS_WIN32)
+ void* GetOSHandle() const { return ThreadHandle; }
+#else
+ pthread_t GetOSHandle() const { return ThreadHandle; }
+#endif
+
+#if defined(OVR_OS_WIN32)
+ ThreadId GetThreadId() const { return IdValue; }
+#else
+ ThreadId GetThreadId() const { return (ThreadId)GetOSHandle(); }
+#endif
+
+ static int GetOSPriority(ThreadPriority);
+ // *** Sleep
+
+ // Sleep secs seconds
+ static bool Sleep(unsigned secs);
+ // Sleep msecs milliseconds
+ static bool MSleep(unsigned msecs);
+
+
+ // *** Debugging functionality
+#if defined(OVR_OS_WIN32)
+ virtual void SetThreadName( const char* name );
+#else
+ virtual void SetThreadName( const char* name ) { OVR_UNUSED(name); }
+#endif
+
+private:
+#if defined(OVR_OS_WIN32)
+ friend unsigned WINAPI Thread_Win32StartFn(void *pthread);
+
+#else
+ friend void *Thread_PthreadStartFn(void * phandle);
+
+ static int InitAttr;
+ static pthread_attr_t Attr;
+#endif
+
+protected:
+ // Thread state flags
+ AtomicInt<UInt32> ThreadFlags;
+ AtomicInt<SInt32> SuspendCount;
+ UPInt StackSize;
+
+ // Hardware processor which this thread is running on.
+ int Processor;
+ ThreadPriority Priority;
+
+#if defined(OVR_OS_WIN32)
+ void* ThreadHandle;
+ volatile ThreadId IdValue;
+
+ // System-specific cleanup function called from destructor
+ void CleanupSystemThread();
+
+#else
+ pthread_t ThreadHandle;
+#endif
+
+ // Exit code of the thread, as returned by Run.
+ int ExitCode;
+
+ // Internal run function.
+ int PRun();
+ // Finishes the thread and releases internal reference to it.
+ void FinishAndRelease();
+
+ void Init(const CreateParams& params);
+
+ // Protected copy constructor
+ Thread(const Thread &source) { OVR_UNUSED(source); }
+
+};
+
+// Returns the unique Id of a thread it is called on, intended for
+// comparison purposes.
+ThreadId GetCurrentThreadId();
+
+
+} // OVR
+
+#endif // OVR_ENABLE_THREADS
+#endif // OVR_Threads_h
diff --git a/LibOVR/Src/Kernel/OVR_ThreadsPthread.cpp b/LibOVR/Src/Kernel/OVR_ThreadsPthread.cpp
index c40d9d8..e8d6753 100644
--- a/LibOVR/Src/Kernel/OVR_ThreadsPthread.cpp
+++ b/LibOVR/Src/Kernel/OVR_ThreadsPthread.cpp
@@ -1,795 +1,795 @@
-
-#include "OVR_Threads.h"
-#include "OVR_Hash.h"
-
-#ifdef OVR_ENABLE_THREADS
-
-#include "OVR_Timer.h"
-#include "OVR_Log.h"
-
-#include <pthread.h>
-#include <time.h>
-
-#ifdef OVR_OS_PS3
-#include <sys/sys_time.h>
-#include <sys/timer.h>
-#include <sys/synchronization.h>
-#define sleep(x) sys_timer_sleep(x)
-#define usleep(x) sys_timer_usleep(x)
-using std::timespec;
-#else
-#include <unistd.h>
-#include <sys/time.h>
-#include <errno.h>
-#endif
-
-namespace OVR {
-
-// ***** Mutex implementation
-
-
-// *** Internal Mutex implementation structure
-
-class MutexImpl : public NewOverrideBase
-{
- // System mutex or semaphore
- pthread_mutex_t SMutex;
- bool Recursive;
- unsigned LockCount;
- pthread_t LockedBy;
-
- friend class WaitConditionImpl;
-
-public:
- // Constructor/destructor
- MutexImpl(Mutex* pmutex, bool recursive = 1);
- ~MutexImpl();
-
- // Locking functions
- void DoLock();
- bool TryLock();
- void Unlock(Mutex* pmutex);
- // Returns 1 if the mutes is currently locked
- bool IsLockedByAnotherThread(Mutex* pmutex);
- bool IsSignaled() const;
-};
-
-pthread_mutexattr_t Lock::RecursiveAttr;
-bool Lock::RecursiveAttrInit = 0;
-
-// *** Constructor/destructor
-MutexImpl::MutexImpl(Mutex* pmutex, bool recursive)
-{
- Recursive = recursive;
- LockCount = 0;
-
- if (Recursive)
- {
- if (!Lock::RecursiveAttrInit)
- {
- pthread_mutexattr_init(&Lock::RecursiveAttr);
- pthread_mutexattr_settype(&Lock::RecursiveAttr, PTHREAD_MUTEX_RECURSIVE);
- Lock::RecursiveAttrInit = 1;
- }
-
- pthread_mutex_init(&SMutex, &Lock::RecursiveAttr);
- }
- else
- pthread_mutex_init(&SMutex, 0);
-}
-
-MutexImpl::~MutexImpl()
-{
- pthread_mutex_destroy(&SMutex);
-}
-
-
-// Lock and try lock
-void MutexImpl::DoLock()
-{
- while (pthread_mutex_lock(&SMutex));
- LockCount++;
- LockedBy = pthread_self();
-}
-
-bool MutexImpl::TryLock()
-{
- if (!pthread_mutex_trylock(&SMutex))
- {
- LockCount++;
- LockedBy = pthread_self();
- return 1;
- }
-
- return 0;
-}
-
-void MutexImpl::Unlock(Mutex* pmutex)
-{
- OVR_ASSERT(pthread_self() == LockedBy && LockCount > 0);
-
- unsigned lockCount;
- LockCount--;
- lockCount = LockCount;
-
- pthread_mutex_unlock(&SMutex);
-}
-
-bool MutexImpl::IsLockedByAnotherThread(Mutex* pmutex)
-{
- // There could be multiple interpretations of IsLocked with respect to current thread
- if (LockCount == 0)
- return 0;
- if (pthread_self() != LockedBy)
- return 1;
- return 0;
-}
-
-bool MutexImpl::IsSignaled() const
-{
- // An mutex is signaled if it is not locked ANYWHERE
- // Note that this is different from IsLockedByAnotherThread function,
- // that takes current thread into account
- return LockCount == 0;
-}
-
-
-// *** Actual Mutex class implementation
-
-Mutex::Mutex(bool recursive)
-{
- // NOTE: RefCount mode already thread-safe for all waitables.
- pImpl = new MutexImpl(this, recursive);
-}
-
-Mutex::~Mutex()
-{
- delete pImpl;
-}
-
-// Lock and try lock
-void Mutex::DoLock()
-{
- pImpl->DoLock();
-}
-bool Mutex::TryLock()
-{
- return pImpl->TryLock();
-}
-void Mutex::Unlock()
-{
- pImpl->Unlock(this);
-}
-bool Mutex::IsLockedByAnotherThread()
-{
- return pImpl->IsLockedByAnotherThread(this);
-}
-
-
-
-//-----------------------------------------------------------------------------------
-// ***** Event
-
-bool Event::Wait(unsigned delay)
-{
- Mutex::Locker lock(&StateMutex);
-
- // Do the correct amount of waiting
- if (delay == OVR_WAIT_INFINITE)
- {
- while(!State)
- StateWaitCondition.Wait(&StateMutex);
- }
- else if (delay)
- {
- if (!State)
- StateWaitCondition.Wait(&StateMutex, delay);
- }
-
- bool state = State;
- // Take care of temporary 'pulsing' of a state
- if (Temporary)
- {
- Temporary = false;
- State = false;
- }
- return state;
-}
-
-void Event::updateState(bool newState, bool newTemp, bool mustNotify)
-{
- Mutex::Locker lock(&StateMutex);
- State = newState;
- Temporary = newTemp;
- if (mustNotify)
- StateWaitCondition.NotifyAll();
-}
-
-
-
-// ***** Wait Condition Implementation
-
-// Internal implementation class
-class WaitConditionImpl : public NewOverrideBase
-{
- pthread_mutex_t SMutex;
- pthread_cond_t Condv;
-
-public:
-
- // Constructor/destructor
- WaitConditionImpl();
- ~WaitConditionImpl();
-
- // Release mutex and wait for condition. The mutex is re-aqured after the wait.
- bool Wait(Mutex *pmutex, unsigned delay = OVR_WAIT_INFINITE);
-
- // Notify a condition, releasing at one object waiting
- void Notify();
- // Notify a condition, releasing all objects waiting
- void NotifyAll();
-};
-
-
-WaitConditionImpl::WaitConditionImpl()
-{
- pthread_mutex_init(&SMutex, 0);
- pthread_cond_init(&Condv, 0);
-}
-
-WaitConditionImpl::~WaitConditionImpl()
-{
- pthread_mutex_destroy(&SMutex);
- pthread_cond_destroy(&Condv);
-}
-
-bool WaitConditionImpl::Wait(Mutex *pmutex, unsigned delay)
-{
- bool result = 1;
- unsigned lockCount = pmutex->pImpl->LockCount;
-
- // Mutex must have been locked
- if (lockCount == 0)
- return 0;
-
- pthread_mutex_lock(&SMutex);
-
- // Finally, release a mutex or semaphore
- if (pmutex->pImpl->Recursive)
- {
- // Release the recursive mutex N times
- pmutex->pImpl->LockCount = 0;
- for(unsigned i=0; i<lockCount; i++)
- pthread_mutex_unlock(&pmutex->pImpl->SMutex);
- }
- else
- {
- pmutex->pImpl->LockCount = 0;
- pthread_mutex_unlock(&pmutex->pImpl->SMutex);
- }
-
- // Note that there is a gap here between mutex.Unlock() and Wait().
- // The other mutex protects this gap.
-
- if (delay == OVR_WAIT_INFINITE)
- pthread_cond_wait(&Condv,&SMutex);
- else
- {
- timespec ts;
-#ifdef OVR_OS_PS3
- sys_time_sec_t s;
- sys_time_nsec_t ns;
- sys_time_get_current_time(&s, &ns);
-
- ts.tv_sec = s + (delay / 1000);
- ts.tv_nsec = ns + (delay % 1000) * 1000000;
-
-#else
- struct timeval tv;
- gettimeofday(&tv, 0);
-
- ts.tv_sec = tv.tv_sec + (delay / 1000);
- ts.tv_nsec = (tv.tv_usec + (delay % 1000) * 1000) * 1000;
-#endif
- if (ts.tv_nsec > 999999999)
- {
- ts.tv_sec++;
- ts.tv_nsec -= 1000000000;
- }
- int r = pthread_cond_timedwait(&Condv,&SMutex, &ts);
- OVR_ASSERT(r == 0 || r == ETIMEDOUT);
- if (r)
- result = 0;
- }
-
- pthread_mutex_unlock(&SMutex);
-
- // Re-aquire the mutex
- for(unsigned i=0; i<lockCount; i++)
- pmutex->DoLock();
-
- // Return the result
- return result;
-}
-
-// Notify a condition, releasing the least object in a queue
-void WaitConditionImpl::Notify()
-{
- pthread_mutex_lock(&SMutex);
- pthread_cond_signal(&Condv);
- pthread_mutex_unlock(&SMutex);
-}
-
-// Notify a condition, releasing all objects waiting
-void WaitConditionImpl::NotifyAll()
-{
- pthread_mutex_lock(&SMutex);
- pthread_cond_broadcast(&Condv);
- pthread_mutex_unlock(&SMutex);
-}
-
-
-
-// *** Actual implementation of WaitCondition
-
-WaitCondition::WaitCondition()
-{
- pImpl = new WaitConditionImpl;
-}
-WaitCondition::~WaitCondition()
-{
- delete pImpl;
-}
-
-bool WaitCondition::Wait(Mutex *pmutex, unsigned delay)
-{
- return pImpl->Wait(pmutex, delay);
-}
-// Notification
-void WaitCondition::Notify()
-{
- pImpl->Notify();
-}
-void WaitCondition::NotifyAll()
-{
- pImpl->NotifyAll();
-}
-
-
-// ***** Current thread
-
-// Per-thread variable
-/*
-static __thread Thread* pCurrentThread = 0;
-
-// Static function to return a pointer to the current thread
-void Thread::InitCurrentThread(Thread *pthread)
-{
- pCurrentThread = pthread;
-}
-
-// Static function to return a pointer to the current thread
-Thread* Thread::GetThread()
-{
- return pCurrentThread;
-}
-*/
-
-
-// *** Thread constructors.
-
-Thread::Thread(UPInt stackSize, int processor)
-{
- // NOTE: RefCount mode already thread-safe for all Waitable objects.
- CreateParams params;
- params.stackSize = stackSize;
- params.processor = processor;
- Init(params);
-}
-
-Thread::Thread(Thread::ThreadFn threadFunction, void* userHandle, UPInt stackSize,
- int processor, Thread::ThreadState initialState)
-{
- CreateParams params(threadFunction, userHandle, stackSize, processor, initialState);
- Init(params);
-}
-
-Thread::Thread(const CreateParams& params)
-{
- Init(params);
-}
-
-void Thread::Init(const CreateParams& params)
-{
- // Clear the variables
- ThreadFlags = 0;
- ThreadHandle = 0;
- ExitCode = 0;
- SuspendCount = 0;
- StackSize = params.stackSize;
- Processor = params.processor;
- Priority = params.priority;
-
- // Clear Function pointers
- ThreadFunction = params.threadFunction;
- UserHandle = params.userHandle;
- if (params.initialState != NotRunning)
- Start(params.initialState);
-}
-
-Thread::~Thread()
-{
- // Thread should not running while object is being destroyed,
- // this would indicate ref-counting issue.
- //OVR_ASSERT(IsRunning() == 0);
-
- // Clean up thread.
- ThreadHandle = 0;
-}
-
-
-
-// *** Overridable User functions.
-
-// Default Run implementation
-int Thread::Run()
-{
- // Call pointer to function, if available.
- return (ThreadFunction) ? ThreadFunction(this, UserHandle) : 0;
-}
-void Thread::OnExit()
-{
-}
-
-
-// Finishes the thread and releases internal reference to it.
-void Thread::FinishAndRelease()
-{
- // Note: thread must be US.
- ThreadFlags &= (UInt32)~(OVR_THREAD_STARTED);
- ThreadFlags |= OVR_THREAD_FINISHED;
-
- // Release our reference; this is equivalent to 'delete this'
- // from the point of view of our thread.
- Release();
-}
-
-
-
-// *** ThreadList - used to track all created threads
-
-class ThreadList : public NewOverrideBase
-{
- //------------------------------------------------------------------------
- struct ThreadHashOp
- {
- size_t operator()(const Thread* ptr)
- {
- return (((size_t)ptr) >> 6) ^ (size_t)ptr;
- }
- };
-
- HashSet<Thread*, ThreadHashOp> ThreadSet;
- Mutex ThreadMutex;
- WaitCondition ThreadsEmpty;
- // Track the root thread that created us.
- pthread_t RootThreadId;
-
- static ThreadList* volatile pRunningThreads;
-
- void addThread(Thread *pthread)
- {
- Mutex::Locker lock(&ThreadMutex);
- ThreadSet.Add(pthread);
- }
-
- void removeThread(Thread *pthread)
- {
- Mutex::Locker lock(&ThreadMutex);
- ThreadSet.Remove(pthread);
- if (ThreadSet.GetSize() == 0)
- ThreadsEmpty.Notify();
- }
-
- void finishAllThreads()
- {
- // Only original root thread can call this.
- OVR_ASSERT(pthread_self() == RootThreadId);
-
- Mutex::Locker lock(&ThreadMutex);
- while (ThreadSet.GetSize() != 0)
- ThreadsEmpty.Wait(&ThreadMutex);
- }
-
-public:
-
- ThreadList()
- {
- RootThreadId = pthread_self();
- }
- ~ThreadList() { }
-
-
- static void AddRunningThread(Thread *pthread)
- {
- // Non-atomic creation ok since only the root thread
- if (!pRunningThreads)
- {
- pRunningThreads = new ThreadList;
- OVR_ASSERT(pRunningThreads);
- }
- pRunningThreads->addThread(pthread);
- }
-
- // NOTE: 'pthread' might be a dead pointer when this is
- // called so it should not be accessed; it is only used
- // for removal.
- static void RemoveRunningThread(Thread *pthread)
- {
- OVR_ASSERT(pRunningThreads);
- pRunningThreads->removeThread(pthread);
- }
-
- static void FinishAllThreads()
- {
- // This is ok because only root thread can wait for other thread finish.
- if (pRunningThreads)
- {
- pRunningThreads->finishAllThreads();
- delete pRunningThreads;
- pRunningThreads = 0;
- }
- }
-};
-
-// By default, we have no thread list.
-ThreadList* volatile ThreadList::pRunningThreads = 0;
-
-
-// FinishAllThreads - exposed publicly in Thread.
-void Thread::FinishAllThreads()
-{
- ThreadList::FinishAllThreads();
-}
-
-// *** Run override
-
-int Thread::PRun()
-{
- // Suspend us on start, if requested
- if (ThreadFlags & OVR_THREAD_START_SUSPENDED)
- {
- Suspend();
- ThreadFlags &= (UInt32)~OVR_THREAD_START_SUSPENDED;
- }
-
- // Call the virtual run function
- ExitCode = Run();
- return ExitCode;
-}
-
-
-
-
-// *** User overridables
-
-bool Thread::GetExitFlag() const
-{
- return (ThreadFlags & OVR_THREAD_EXIT) != 0;
-}
-
-void Thread::SetExitFlag(bool exitFlag)
-{
- // The below is atomic since ThreadFlags is AtomicInt.
- if (exitFlag)
- ThreadFlags |= OVR_THREAD_EXIT;
- else
- ThreadFlags &= (UInt32) ~OVR_THREAD_EXIT;
-}
-
-
-// Determines whether the thread was running and is now finished
-bool Thread::IsFinished() const
-{
- return (ThreadFlags & OVR_THREAD_FINISHED) != 0;
-}
-// Determines whether the thread is suspended
-bool Thread::IsSuspended() const
-{
- return SuspendCount > 0;
-}
-// Returns current thread state
-Thread::ThreadState Thread::GetThreadState() const
-{
- if (IsSuspended())
- return Suspended;
- if (ThreadFlags & OVR_THREAD_STARTED)
- return Running;
- return NotRunning;
-}
-/*
-static const char* mapsched_policy(int policy)
-{
- switch(policy)
- {
- case SCHED_OTHER:
- return "SCHED_OTHER";
- case SCHED_RR:
- return "SCHED_RR";
- case SCHED_FIFO:
- return "SCHED_FIFO";
-
- }
- return "UNKNOWN";
-}
- int policy;
- sched_param sparam;
- pthread_getschedparam(pthread_self(), &policy, &sparam);
- int max_prior = sched_get_priority_max(policy);
- int min_prior = sched_get_priority_min(policy);
- printf(" !!!! policy: %s, priority: %d, max priority: %d, min priority: %d\n", mapsched_policy(policy), sparam.sched_priority, max_prior, min_prior);
-#include <stdio.h>
-*/
-// ***** Thread management
-
-// The actual first function called on thread start
-void* Thread_PthreadStartFn(void* phandle)
-{
- Thread* pthread = (Thread*)phandle;
- int result = pthread->PRun();
- // Signal the thread as done and release it atomically.
- pthread->FinishAndRelease();
- // At this point Thread object might be dead; however we can still pass
- // it to RemoveRunningThread since it is only used as a key there.
- ThreadList::RemoveRunningThread(pthread);
- return (void*) result;
-}
-
-int Thread::InitAttr = 0;
-pthread_attr_t Thread::Attr;
-
-/* static */
-int Thread::GetOSPriority(ThreadPriority p)
-//static inline int MapToSystemPrority(Thread::ThreadPriority p)
-{
-#ifdef OVR_OS_PS3
- switch(p)
- {
- case Thread::CriticalPriority: return 0;
- case Thread::HighestPriority: return 300;
- case Thread::AboveNormalPriority: return 600;
- case Thread::NormalPriority: return 1000;
- case Thread::BelowNormalPriority: return 1500;
- case Thread::LowestPriority: return 2500;
- case Thread::IdlePriority: return 3071;
- } return 1000;
-#else
- OVR_UNUSED(p);
- return -1;
-#endif
-}
-
-bool Thread::Start(ThreadState initialState)
-{
- if (initialState == NotRunning)
- return 0;
- if (GetThreadState() != NotRunning)
- {
- OVR_DEBUG_LOG(("Thread::Start failed - thread %p already running", this));
- return 0;
- }
-
- if (!InitAttr)
- {
- pthread_attr_init(&Attr);
- pthread_attr_setdetachstate(&Attr, PTHREAD_CREATE_DETACHED);
- pthread_attr_setstacksize(&Attr, 128 * 1024);
- sched_param sparam;
- sparam.sched_priority = Thread::GetOSPriority(NormalPriority);
- pthread_attr_setschedparam(&Attr, &sparam);
- InitAttr = 1;
- }
-
- ExitCode = 0;
- SuspendCount = 0;
- ThreadFlags = (initialState == Running) ? 0 : OVR_THREAD_START_SUSPENDED;
-
- // AddRef to us until the thread is finished
- AddRef();
- ThreadList::AddRunningThread(this);
-
- int result;
- if (StackSize != 128 * 1024 || Priority != NormalPriority)
- {
- pthread_attr_t attr;
-
- pthread_attr_init(&attr);
- pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
- pthread_attr_setstacksize(&attr, StackSize);
- sched_param sparam;
- sparam.sched_priority = Thread::GetOSPriority(Priority);
- pthread_attr_setschedparam(&attr, &sparam);
- result = pthread_create(&ThreadHandle, &attr, Thread_PthreadStartFn, this);
- pthread_attr_destroy(&attr);
- }
- else
- result = pthread_create(&ThreadHandle, &Attr, Thread_PthreadStartFn, this);
-
- if (result)
- {
- ThreadFlags = 0;
- Release();
- ThreadList::RemoveRunningThread(this);
- return 0;
- }
- return 1;
-}
-
-
-// Suspend the thread until resumed
-bool Thread::Suspend()
-{
- OVR_DEBUG_LOG(("Thread::Suspend - cannot suspend threads on this system"));
- return 0;
-}
-
-// Resumes currently suspended thread
-bool Thread::Resume()
-{
- return 0;
-}
-
-
-// Quits with an exit code
-void Thread::Exit(int exitCode)
-{
- // Can only exist the current thread
- // if (GetThread() != this)
- // return;
-
- // Call the virtual OnExit function
- OnExit();
-
- // Signal this thread object as done and release it's references.
- FinishAndRelease();
- ThreadList::RemoveRunningThread(this);
-
- pthread_exit((void *) exitCode);
-}
-
-ThreadId GetCurrentThreadId()
-{
- return (void*)pthread_self();
-}
-
-// *** Sleep functions
-
-/* static */
-bool Thread::Sleep(unsigned secs)
-{
- sleep(secs);
- return 1;
-}
-/* static */
-bool Thread::MSleep(unsigned msecs)
-{
- usleep(msecs*1000);
- return 1;
-}
-
-/* static */
-int Thread::GetCPUCount()
-{
- return 1;
-}
-
-
-#ifdef OVR_OS_PS3
-
-sys_lwmutex_attribute_t Lock::LockAttr = { SYS_SYNC_PRIORITY, SYS_SYNC_RECURSIVE };
-
-#endif
-
-}
-
-#endif // OVR_ENABLE_THREADS
+
+#include "OVR_Threads.h"
+#include "OVR_Hash.h"
+
+#ifdef OVR_ENABLE_THREADS
+
+#include "OVR_Timer.h"
+#include "OVR_Log.h"
+
+#include <pthread.h>
+#include <time.h>
+
+#ifdef OVR_OS_PS3
+#include <sys/sys_time.h>
+#include <sys/timer.h>
+#include <sys/synchronization.h>
+#define sleep(x) sys_timer_sleep(x)
+#define usleep(x) sys_timer_usleep(x)
+using std::timespec;
+#else
+#include <unistd.h>
+#include <sys/time.h>
+#include <errno.h>
+#endif
+
+namespace OVR {
+
+// ***** Mutex implementation
+
+
+// *** Internal Mutex implementation structure
+
+class MutexImpl : public NewOverrideBase
+{
+ // System mutex or semaphore
+ pthread_mutex_t SMutex;
+ bool Recursive;
+ unsigned LockCount;
+ pthread_t LockedBy;
+
+ friend class WaitConditionImpl;
+
+public:
+ // Constructor/destructor
+ MutexImpl(Mutex* pmutex, bool recursive = 1);
+ ~MutexImpl();
+
+ // Locking functions
+ void DoLock();
+ bool TryLock();
+ void Unlock(Mutex* pmutex);
+ // Returns 1 if the mutes is currently locked
+ bool IsLockedByAnotherThread(Mutex* pmutex);
+ bool IsSignaled() const;
+};
+
+pthread_mutexattr_t Lock::RecursiveAttr;
+bool Lock::RecursiveAttrInit = 0;
+
+// *** Constructor/destructor
+MutexImpl::MutexImpl(Mutex* pmutex, bool recursive)
+{
+ Recursive = recursive;
+ LockCount = 0;
+
+ if (Recursive)
+ {
+ if (!Lock::RecursiveAttrInit)
+ {
+ pthread_mutexattr_init(&Lock::RecursiveAttr);
+ pthread_mutexattr_settype(&Lock::RecursiveAttr, PTHREAD_MUTEX_RECURSIVE);
+ Lock::RecursiveAttrInit = 1;
+ }
+
+ pthread_mutex_init(&SMutex, &Lock::RecursiveAttr);
+ }
+ else
+ pthread_mutex_init(&SMutex, 0);
+}
+
+MutexImpl::~MutexImpl()
+{
+ pthread_mutex_destroy(&SMutex);
+}
+
+
+// Lock and try lock
+void MutexImpl::DoLock()
+{
+ while (pthread_mutex_lock(&SMutex));
+ LockCount++;
+ LockedBy = pthread_self();
+}
+
+bool MutexImpl::TryLock()
+{
+ if (!pthread_mutex_trylock(&SMutex))
+ {
+ LockCount++;
+ LockedBy = pthread_self();
+ return 1;
+ }
+
+ return 0;
+}
+
+void MutexImpl::Unlock(Mutex* pmutex)
+{
+ OVR_ASSERT(pthread_self() == LockedBy && LockCount > 0);
+
+ unsigned lockCount;
+ LockCount--;
+ lockCount = LockCount;
+
+ pthread_mutex_unlock(&SMutex);
+}
+
+bool MutexImpl::IsLockedByAnotherThread(Mutex* pmutex)
+{
+ // There could be multiple interpretations of IsLocked with respect to current thread
+ if (LockCount == 0)
+ return 0;
+ if (pthread_self() != LockedBy)
+ return 1;
+ return 0;
+}
+
+bool MutexImpl::IsSignaled() const
+{
+ // An mutex is signaled if it is not locked ANYWHERE
+ // Note that this is different from IsLockedByAnotherThread function,
+ // that takes current thread into account
+ return LockCount == 0;
+}
+
+
+// *** Actual Mutex class implementation
+
+Mutex::Mutex(bool recursive)
+{
+ // NOTE: RefCount mode already thread-safe for all waitables.
+ pImpl = new MutexImpl(this, recursive);
+}
+
+Mutex::~Mutex()
+{
+ delete pImpl;
+}
+
+// Lock and try lock
+void Mutex::DoLock()
+{
+ pImpl->DoLock();
+}
+bool Mutex::TryLock()
+{
+ return pImpl->TryLock();
+}
+void Mutex::Unlock()
+{
+ pImpl->Unlock(this);
+}
+bool Mutex::IsLockedByAnotherThread()
+{
+ return pImpl->IsLockedByAnotherThread(this);
+}
+
+
+
+//-----------------------------------------------------------------------------------
+// ***** Event
+
+bool Event::Wait(unsigned delay)
+{
+ Mutex::Locker lock(&StateMutex);
+
+ // Do the correct amount of waiting
+ if (delay == OVR_WAIT_INFINITE)
+ {
+ while(!State)
+ StateWaitCondition.Wait(&StateMutex);
+ }
+ else if (delay)
+ {
+ if (!State)
+ StateWaitCondition.Wait(&StateMutex, delay);
+ }
+
+ bool state = State;
+ // Take care of temporary 'pulsing' of a state
+ if (Temporary)
+ {
+ Temporary = false;
+ State = false;
+ }
+ return state;
+}
+
+void Event::updateState(bool newState, bool newTemp, bool mustNotify)
+{
+ Mutex::Locker lock(&StateMutex);
+ State = newState;
+ Temporary = newTemp;
+ if (mustNotify)
+ StateWaitCondition.NotifyAll();
+}
+
+
+
+// ***** Wait Condition Implementation
+
+// Internal implementation class
+class WaitConditionImpl : public NewOverrideBase
+{
+ pthread_mutex_t SMutex;
+ pthread_cond_t Condv;
+
+public:
+
+ // Constructor/destructor
+ WaitConditionImpl();
+ ~WaitConditionImpl();
+
+ // Release mutex and wait for condition. The mutex is re-aqured after the wait.
+ bool Wait(Mutex *pmutex, unsigned delay = OVR_WAIT_INFINITE);
+
+ // Notify a condition, releasing at one object waiting
+ void Notify();
+ // Notify a condition, releasing all objects waiting
+ void NotifyAll();
+};
+
+
+WaitConditionImpl::WaitConditionImpl()
+{
+ pthread_mutex_init(&SMutex, 0);
+ pthread_cond_init(&Condv, 0);
+}
+
+WaitConditionImpl::~WaitConditionImpl()
+{
+ pthread_mutex_destroy(&SMutex);
+ pthread_cond_destroy(&Condv);
+}
+
+bool WaitConditionImpl::Wait(Mutex *pmutex, unsigned delay)
+{
+ bool result = 1;
+ unsigned lockCount = pmutex->pImpl->LockCount;
+
+ // Mutex must have been locked
+ if (lockCount == 0)
+ return 0;
+
+ pthread_mutex_lock(&SMutex);
+
+ // Finally, release a mutex or semaphore
+ if (pmutex->pImpl->Recursive)
+ {
+ // Release the recursive mutex N times
+ pmutex->pImpl->LockCount = 0;
+ for(unsigned i=0; i<lockCount; i++)
+ pthread_mutex_unlock(&pmutex->pImpl->SMutex);
+ }
+ else
+ {
+ pmutex->pImpl->LockCount = 0;
+ pthread_mutex_unlock(&pmutex->pImpl->SMutex);
+ }
+
+ // Note that there is a gap here between mutex.Unlock() and Wait().
+ // The other mutex protects this gap.
+
+ if (delay == OVR_WAIT_INFINITE)
+ pthread_cond_wait(&Condv,&SMutex);
+ else
+ {
+ timespec ts;
+#ifdef OVR_OS_PS3
+ sys_time_sec_t s;
+ sys_time_nsec_t ns;
+ sys_time_get_current_time(&s, &ns);
+
+ ts.tv_sec = s + (delay / 1000);
+ ts.tv_nsec = ns + (delay % 1000) * 1000000;
+
+#else
+ struct timeval tv;
+ gettimeofday(&tv, 0);
+
+ ts.tv_sec = tv.tv_sec + (delay / 1000);
+ ts.tv_nsec = (tv.tv_usec + (delay % 1000) * 1000) * 1000;
+#endif
+ if (ts.tv_nsec > 999999999)
+ {
+ ts.tv_sec++;
+ ts.tv_nsec -= 1000000000;
+ }
+ int r = pthread_cond_timedwait(&Condv,&SMutex, &ts);
+ OVR_ASSERT(r == 0 || r == ETIMEDOUT);
+ if (r)
+ result = 0;
+ }
+
+ pthread_mutex_unlock(&SMutex);
+
+ // Re-aquire the mutex
+ for(unsigned i=0; i<lockCount; i++)
+ pmutex->DoLock();
+
+ // Return the result
+ return result;
+}
+
+// Notify a condition, releasing the least object in a queue
+void WaitConditionImpl::Notify()
+{
+ pthread_mutex_lock(&SMutex);
+ pthread_cond_signal(&Condv);
+ pthread_mutex_unlock(&SMutex);
+}
+
+// Notify a condition, releasing all objects waiting
+void WaitConditionImpl::NotifyAll()
+{
+ pthread_mutex_lock(&SMutex);
+ pthread_cond_broadcast(&Condv);
+ pthread_mutex_unlock(&SMutex);
+}
+
+
+
+// *** Actual implementation of WaitCondition
+
+WaitCondition::WaitCondition()
+{
+ pImpl = new WaitConditionImpl;
+}
+WaitCondition::~WaitCondition()
+{
+ delete pImpl;
+}
+
+bool WaitCondition::Wait(Mutex *pmutex, unsigned delay)
+{
+ return pImpl->Wait(pmutex, delay);
+}
+// Notification
+void WaitCondition::Notify()
+{
+ pImpl->Notify();
+}
+void WaitCondition::NotifyAll()
+{
+ pImpl->NotifyAll();
+}
+
+
+// ***** Current thread
+
+// Per-thread variable
+/*
+static __thread Thread* pCurrentThread = 0;
+
+// Static function to return a pointer to the current thread
+void Thread::InitCurrentThread(Thread *pthread)
+{
+ pCurrentThread = pthread;
+}
+
+// Static function to return a pointer to the current thread
+Thread* Thread::GetThread()
+{
+ return pCurrentThread;
+}
+*/
+
+
+// *** Thread constructors.
+
+Thread::Thread(UPInt stackSize, int processor)
+{
+ // NOTE: RefCount mode already thread-safe for all Waitable objects.
+ CreateParams params;
+ params.stackSize = stackSize;
+ params.processor = processor;
+ Init(params);
+}
+
+Thread::Thread(Thread::ThreadFn threadFunction, void* userHandle, UPInt stackSize,
+ int processor, Thread::ThreadState initialState)
+{
+ CreateParams params(threadFunction, userHandle, stackSize, processor, initialState);
+ Init(params);
+}
+
+Thread::Thread(const CreateParams& params)
+{
+ Init(params);
+}
+
+void Thread::Init(const CreateParams& params)
+{
+ // Clear the variables
+ ThreadFlags = 0;
+ ThreadHandle = 0;
+ ExitCode = 0;
+ SuspendCount = 0;
+ StackSize = params.stackSize;
+ Processor = params.processor;
+ Priority = params.priority;
+
+ // Clear Function pointers
+ ThreadFunction = params.threadFunction;
+ UserHandle = params.userHandle;
+ if (params.initialState != NotRunning)
+ Start(params.initialState);
+}
+
+Thread::~Thread()
+{
+ // Thread should not running while object is being destroyed,
+ // this would indicate ref-counting issue.
+ //OVR_ASSERT(IsRunning() == 0);
+
+ // Clean up thread.
+ ThreadHandle = 0;
+}
+
+
+
+// *** Overridable User functions.
+
+// Default Run implementation
+int Thread::Run()
+{
+ // Call pointer to function, if available.
+ return (ThreadFunction) ? ThreadFunction(this, UserHandle) : 0;
+}
+void Thread::OnExit()
+{
+}
+
+
+// Finishes the thread and releases internal reference to it.
+void Thread::FinishAndRelease()
+{
+ // Note: thread must be US.
+ ThreadFlags &= (UInt32)~(OVR_THREAD_STARTED);
+ ThreadFlags |= OVR_THREAD_FINISHED;
+
+ // Release our reference; this is equivalent to 'delete this'
+ // from the point of view of our thread.
+ Release();
+}
+
+
+
+// *** ThreadList - used to track all created threads
+
+class ThreadList : public NewOverrideBase
+{
+ //------------------------------------------------------------------------
+ struct ThreadHashOp
+ {
+ size_t operator()(const Thread* ptr)
+ {
+ return (((size_t)ptr) >> 6) ^ (size_t)ptr;
+ }
+ };
+
+ HashSet<Thread*, ThreadHashOp> ThreadSet;
+ Mutex ThreadMutex;
+ WaitCondition ThreadsEmpty;
+ // Track the root thread that created us.
+ pthread_t RootThreadId;
+
+ static ThreadList* volatile pRunningThreads;
+
+ void addThread(Thread *pthread)
+ {
+ Mutex::Locker lock(&ThreadMutex);
+ ThreadSet.Add(pthread);
+ }
+
+ void removeThread(Thread *pthread)
+ {
+ Mutex::Locker lock(&ThreadMutex);
+ ThreadSet.Remove(pthread);
+ if (ThreadSet.GetSize() == 0)
+ ThreadsEmpty.Notify();
+ }
+
+ void finishAllThreads()
+ {
+ // Only original root thread can call this.
+ OVR_ASSERT(pthread_self() == RootThreadId);
+
+ Mutex::Locker lock(&ThreadMutex);
+ while (ThreadSet.GetSize() != 0)
+ ThreadsEmpty.Wait(&ThreadMutex);
+ }
+
+public:
+
+ ThreadList()
+ {
+ RootThreadId = pthread_self();
+ }
+ ~ThreadList() { }
+
+
+ static void AddRunningThread(Thread *pthread)
+ {
+ // Non-atomic creation ok since only the root thread
+ if (!pRunningThreads)
+ {
+ pRunningThreads = new ThreadList;
+ OVR_ASSERT(pRunningThreads);
+ }
+ pRunningThreads->addThread(pthread);
+ }
+
+ // NOTE: 'pthread' might be a dead pointer when this is
+ // called so it should not be accessed; it is only used
+ // for removal.
+ static void RemoveRunningThread(Thread *pthread)
+ {
+ OVR_ASSERT(pRunningThreads);
+ pRunningThreads->removeThread(pthread);
+ }
+
+ static void FinishAllThreads()
+ {
+ // This is ok because only root thread can wait for other thread finish.
+ if (pRunningThreads)
+ {
+ pRunningThreads->finishAllThreads();
+ delete pRunningThreads;
+ pRunningThreads = 0;
+ }
+ }
+};
+
+// By default, we have no thread list.
+ThreadList* volatile ThreadList::pRunningThreads = 0;
+
+
+// FinishAllThreads - exposed publicly in Thread.
+void Thread::FinishAllThreads()
+{
+ ThreadList::FinishAllThreads();
+}
+
+// *** Run override
+
+int Thread::PRun()
+{
+ // Suspend us on start, if requested
+ if (ThreadFlags & OVR_THREAD_START_SUSPENDED)
+ {
+ Suspend();
+ ThreadFlags &= (UInt32)~OVR_THREAD_START_SUSPENDED;
+ }
+
+ // Call the virtual run function
+ ExitCode = Run();
+ return ExitCode;
+}
+
+
+
+
+// *** User overridables
+
+bool Thread::GetExitFlag() const
+{
+ return (ThreadFlags & OVR_THREAD_EXIT) != 0;
+}
+
+void Thread::SetExitFlag(bool exitFlag)
+{
+ // The below is atomic since ThreadFlags is AtomicInt.
+ if (exitFlag)
+ ThreadFlags |= OVR_THREAD_EXIT;
+ else
+ ThreadFlags &= (UInt32) ~OVR_THREAD_EXIT;
+}
+
+
+// Determines whether the thread was running and is now finished
+bool Thread::IsFinished() const
+{
+ return (ThreadFlags & OVR_THREAD_FINISHED) != 0;
+}
+// Determines whether the thread is suspended
+bool Thread::IsSuspended() const
+{
+ return SuspendCount > 0;
+}
+// Returns current thread state
+Thread::ThreadState Thread::GetThreadState() const
+{
+ if (IsSuspended())
+ return Suspended;
+ if (ThreadFlags & OVR_THREAD_STARTED)
+ return Running;
+ return NotRunning;
+}
+/*
+static const char* mapsched_policy(int policy)
+{
+ switch(policy)
+ {
+ case SCHED_OTHER:
+ return "SCHED_OTHER";
+ case SCHED_RR:
+ return "SCHED_RR";
+ case SCHED_FIFO:
+ return "SCHED_FIFO";
+
+ }
+ return "UNKNOWN";
+}
+ int policy;
+ sched_param sparam;
+ pthread_getschedparam(pthread_self(), &policy, &sparam);
+ int max_prior = sched_get_priority_max(policy);
+ int min_prior = sched_get_priority_min(policy);
+ printf(" !!!! policy: %s, priority: %d, max priority: %d, min priority: %d\n", mapsched_policy(policy), sparam.sched_priority, max_prior, min_prior);
+#include <stdio.h>
+*/
+// ***** Thread management
+
+// The actual first function called on thread start
+void* Thread_PthreadStartFn(void* phandle)
+{
+ Thread* pthread = (Thread*)phandle;
+ int result = pthread->PRun();
+ // Signal the thread as done and release it atomically.
+ pthread->FinishAndRelease();
+ // At this point Thread object might be dead; however we can still pass
+ // it to RemoveRunningThread since it is only used as a key there.
+ ThreadList::RemoveRunningThread(pthread);
+ return (void*) result;
+}
+
+int Thread::InitAttr = 0;
+pthread_attr_t Thread::Attr;
+
+/* static */
+int Thread::GetOSPriority(ThreadPriority p)
+//static inline int MapToSystemPrority(Thread::ThreadPriority p)
+{
+#ifdef OVR_OS_PS3
+ switch(p)
+ {
+ case Thread::CriticalPriority: return 0;
+ case Thread::HighestPriority: return 300;
+ case Thread::AboveNormalPriority: return 600;
+ case Thread::NormalPriority: return 1000;
+ case Thread::BelowNormalPriority: return 1500;
+ case Thread::LowestPriority: return 2500;
+ case Thread::IdlePriority: return 3071;
+ } return 1000;
+#else
+ OVR_UNUSED(p);
+ return -1;
+#endif
+}
+
+bool Thread::Start(ThreadState initialState)
+{
+ if (initialState == NotRunning)
+ return 0;
+ if (GetThreadState() != NotRunning)
+ {
+ OVR_DEBUG_LOG(("Thread::Start failed - thread %p already running", this));
+ return 0;
+ }
+
+ if (!InitAttr)
+ {
+ pthread_attr_init(&Attr);
+ pthread_attr_setdetachstate(&Attr, PTHREAD_CREATE_DETACHED);
+ pthread_attr_setstacksize(&Attr, 128 * 1024);
+ sched_param sparam;
+ sparam.sched_priority = Thread::GetOSPriority(NormalPriority);
+ pthread_attr_setschedparam(&Attr, &sparam);
+ InitAttr = 1;
+ }
+
+ ExitCode = 0;
+ SuspendCount = 0;
+ ThreadFlags = (initialState == Running) ? 0 : OVR_THREAD_START_SUSPENDED;
+
+ // AddRef to us until the thread is finished
+ AddRef();
+ ThreadList::AddRunningThread(this);
+
+ int result;
+ if (StackSize != 128 * 1024 || Priority != NormalPriority)
+ {
+ pthread_attr_t attr;
+
+ pthread_attr_init(&attr);
+ pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
+ pthread_attr_setstacksize(&attr, StackSize);
+ sched_param sparam;
+ sparam.sched_priority = Thread::GetOSPriority(Priority);
+ pthread_attr_setschedparam(&attr, &sparam);
+ result = pthread_create(&ThreadHandle, &attr, Thread_PthreadStartFn, this);
+ pthread_attr_destroy(&attr);
+ }
+ else
+ result = pthread_create(&ThreadHandle, &Attr, Thread_PthreadStartFn, this);
+
+ if (result)
+ {
+ ThreadFlags = 0;
+ Release();
+ ThreadList::RemoveRunningThread(this);
+ return 0;
+ }
+ return 1;
+}
+
+
+// Suspend the thread until resumed
+bool Thread::Suspend()
+{
+ OVR_DEBUG_LOG(("Thread::Suspend - cannot suspend threads on this system"));
+ return 0;
+}
+
+// Resumes currently suspended thread
+bool Thread::Resume()
+{
+ return 0;
+}
+
+
+// Quits with an exit code
+void Thread::Exit(int exitCode)
+{
+ // Can only exist the current thread
+ // if (GetThread() != this)
+ // return;
+
+ // Call the virtual OnExit function
+ OnExit();
+
+ // Signal this thread object as done and release it's references.
+ FinishAndRelease();
+ ThreadList::RemoveRunningThread(this);
+
+ pthread_exit((void *) exitCode);
+}
+
+ThreadId GetCurrentThreadId()
+{
+ return (void*)pthread_self();
+}
+
+// *** Sleep functions
+
+/* static */
+bool Thread::Sleep(unsigned secs)
+{
+ sleep(secs);
+ return 1;
+}
+/* static */
+bool Thread::MSleep(unsigned msecs)
+{
+ usleep(msecs*1000);
+ return 1;
+}
+
+/* static */
+int Thread::GetCPUCount()
+{
+ return 1;
+}
+
+
+#ifdef OVR_OS_PS3
+
+sys_lwmutex_attribute_t Lock::LockAttr = { SYS_SYNC_PRIORITY, SYS_SYNC_RECURSIVE };
+
+#endif
+
+}
+
+#endif // OVR_ENABLE_THREADS
diff --git a/LibOVR/Src/Kernel/OVR_ThreadsWinAPI.cpp b/LibOVR/Src/Kernel/OVR_ThreadsWinAPI.cpp
index fa3962e..7a75872 100644
--- a/LibOVR/Src/Kernel/OVR_ThreadsWinAPI.cpp
+++ b/LibOVR/Src/Kernel/OVR_ThreadsWinAPI.cpp
@@ -1,994 +1,994 @@
-/************************************************************************************
-
-Filename : OVR_ThreadsWinAPI.cpp
-Platform : WinAPI
-Content : Windows specific thread-related (safe) functionality
-Created : September 19, 2012
-Notes :
-
-Copyright : Copyright 2012 Oculus VR, Inc. All Rights reserved.
-
-Use of this software is subject to the terms of the Oculus license
-agreement provided at the time of installation or download, or which
-otherwise accompanies this software in either electronic or hard copy form.
-
-************************************************************************************/
-
-#include "OVR_Threads.h"
-#include "OVR_Hash.h"
-#include "OVR_Log.h"
-
-#ifdef OVR_ENABLE_THREADS
-
-// For _beginthreadex / _endtheadex
-#include <process.h>
-
-namespace OVR {
-
-
-//-----------------------------------------------------------------------------------
-// *** Internal Mutex implementation class
-
-class MutexImpl : public NewOverrideBase
-{
- // System mutex or semaphore
- HANDLE hMutexOrSemaphore;
- bool Recursive;
- volatile unsigned LockCount;
-
- friend class WaitConditionImpl;
-
-public:
- // Constructor/destructor
- MutexImpl(bool recursive = 1);
- ~MutexImpl();
-
- // Locking functions
- void DoLock();
- bool TryLock();
- void Unlock(Mutex* pmutex);
- // Returns 1 if the mutes is currently locked
- bool IsLockedByAnotherThread(Mutex* pmutex);
-};
-
-// *** Constructor/destructor
-MutexImpl::MutexImpl(bool recursive)
-{
- Recursive = recursive;
- LockCount = 0;
- hMutexOrSemaphore = Recursive ? CreateMutex(NULL, 0, NULL) : CreateSemaphore(NULL, 1, 1, NULL);
-}
-MutexImpl::~MutexImpl()
-{
- CloseHandle(hMutexOrSemaphore);
-}
-
-
-// Lock and try lock
-void MutexImpl::DoLock()
-{
- if (::WaitForSingleObject(hMutexOrSemaphore, INFINITE) != WAIT_OBJECT_0)
- return;
- LockCount++;
-}
-
-bool MutexImpl::TryLock()
-{
- DWORD ret;
- if ((ret=::WaitForSingleObject(hMutexOrSemaphore, 0)) != WAIT_OBJECT_0)
- return 0;
- LockCount++;
- return 1;
-}
-
-void MutexImpl::Unlock(Mutex* pmutex)
-{
- OVR_UNUSED(pmutex);
-
- unsigned lockCount;
- LockCount--;
- lockCount = LockCount;
-
- // Release mutex
- if ((Recursive ? ReleaseMutex(hMutexOrSemaphore) :
- ReleaseSemaphore(hMutexOrSemaphore, 1, NULL)) != 0)
- {
- // This used to call Wait handlers if lockCount == 0.
- }
-}
-
-bool MutexImpl::IsLockedByAnotherThread(Mutex* pmutex)
-{
- // There could be multiple interpretations of IsLocked with respect to current thread
- if (LockCount == 0)
- return 0;
- if (!TryLock())
- return 1;
- Unlock(pmutex);
- return 0;
-}
-
-/*
-bool MutexImpl::IsSignaled() const
-{
- // An mutex is signaled if it is not locked ANYWHERE
- // Note that this is different from IsLockedByAnotherThread function,
- // that takes current thread into account
- return LockCount == 0;
-}
-*/
-
-
-// *** Actual Mutex class implementation
-
-Mutex::Mutex(bool recursive)
-{
- pImpl = new MutexImpl(recursive);
-}
-Mutex::~Mutex()
-{
- delete pImpl;
-}
-
-// Lock and try lock
-void Mutex::DoLock()
-{
- pImpl->DoLock();
-}
-bool Mutex::TryLock()
-{
- return pImpl->TryLock();
-}
-void Mutex::Unlock()
-{
- pImpl->Unlock(this);
-}
-bool Mutex::IsLockedByAnotherThread()
-{
- return pImpl->IsLockedByAnotherThread(this);
-}
-
-//-----------------------------------------------------------------------------------
-// ***** Event
-
-bool Event::Wait(unsigned delay)
-{
- Mutex::Locker lock(&StateMutex);
-
- // Do the correct amount of waiting
- if (delay == OVR_WAIT_INFINITE)
- {
- while(!State)
- StateWaitCondition.Wait(&StateMutex);
- }
- else if (delay)
- {
- if (!State)
- StateWaitCondition.Wait(&StateMutex, delay);
- }
-
- bool state = State;
- // Take care of temporary 'pulsing' of a state
- if (Temporary)
- {
- Temporary = false;
- State = false;
- }
- return state;
-}
-
-void Event::updateState(bool newState, bool newTemp, bool mustNotify)
-{
- Mutex::Locker lock(&StateMutex);
- State = newState;
- Temporary = newTemp;
- if (mustNotify)
- StateWaitCondition.NotifyAll();
-}
-
-
-//-----------------------------------------------------------------------------------
-// ***** Win32 Wait Condition Implementation
-
-// Internal implementation class
-class WaitConditionImpl : public NewOverrideBase
-{
- // Event pool entries for extra events
- struct EventPoolEntry : public NewOverrideBase
- {
- HANDLE hEvent;
- EventPoolEntry *pNext;
- EventPoolEntry *pPrev;
- };
-
- Lock WaitQueueLoc;
- // Stores free events that can be used later
- EventPoolEntry * pFreeEventList;
-
- // A queue of waiting objects to be signaled
- EventPoolEntry* pQueueHead;
- EventPoolEntry* pQueueTail;
-
- // Allocation functions for free events
- EventPoolEntry* GetNewEvent();
- void ReleaseEvent(EventPoolEntry* pevent);
-
- // Queue operations
- void QueuePush(EventPoolEntry* pentry);
- EventPoolEntry* QueuePop();
- void QueueFindAndRemove(EventPoolEntry* pentry);
-
-public:
-
- // Constructor/destructor
- WaitConditionImpl();
- ~WaitConditionImpl();
-
- // Release mutex and wait for condition. The mutex is re-acqured after the wait.
- bool Wait(Mutex *pmutex, unsigned delay = OVR_WAIT_INFINITE);
-
- // Notify a condition, releasing at one object waiting
- void Notify();
- // Notify a condition, releasing all objects waiting
- void NotifyAll();
-};
-
-
-
-WaitConditionImpl::WaitConditionImpl()
-{
- pFreeEventList = 0;
- pQueueHead =
- pQueueTail = 0;
-}
-
-WaitConditionImpl::~WaitConditionImpl()
-{
- // Free all the resources
- EventPoolEntry* p = pFreeEventList;
- EventPoolEntry* pentry;
-
- while(p)
- {
- // Move to next
- pentry = p;
- p = p->pNext;
- // Delete old
- ::CloseHandle(pentry->hEvent);
- delete pentry;
- }
- // Shouldn't we also consider the queue?
-
- // To be safe
- pFreeEventList = 0;
- pQueueHead =
- pQueueTail = 0;
-}
-
-
-// Allocation functions for free events
-WaitConditionImpl::EventPoolEntry* WaitConditionImpl::GetNewEvent()
-{
- EventPoolEntry* pentry;
-
- // If there are any free nodes, use them
- if (pFreeEventList)
- {
- pentry = pFreeEventList;
- pFreeEventList = pFreeEventList->pNext;
- }
- else
- {
- // Allocate a new node
- pentry = new EventPoolEntry;
- pentry->pNext = 0;
- pentry->pPrev = 0;
- // Non-signaled manual event
- pentry->hEvent = ::CreateEvent(NULL, TRUE, 0, NULL);
- }
-
- return pentry;
-}
-
-void WaitConditionImpl::ReleaseEvent(EventPoolEntry* pevent)
-{
- // Mark event as non-signaled
- ::ResetEvent(pevent->hEvent);
- // And add it to free pool
- pevent->pNext = pFreeEventList;
- pevent->pPrev = 0;
- pFreeEventList = pevent;
-}
-
-// Queue operations
-void WaitConditionImpl::QueuePush(EventPoolEntry* pentry)
-{
- // Items already exist? Just add to tail
- if (pQueueTail)
- {
- pentry->pPrev = pQueueTail;
- pQueueTail->pNext = pentry;
- pentry->pNext = 0;
- pQueueTail = pentry;
- }
- else
- {
- // No items in queue
- pentry->pNext =
- pentry->pPrev = 0;
- pQueueHead =
- pQueueTail = pentry;
- }
-}
-
-WaitConditionImpl::EventPoolEntry* WaitConditionImpl::QueuePop()
-{
- EventPoolEntry* pentry = pQueueHead;
-
- // No items, null pointer
- if (pentry)
- {
- // More items after this one? just grab the first item
- if (pQueueHead->pNext)
- {
- pQueueHead = pentry->pNext;
- pQueueHead->pPrev = 0;
- }
- else
- {
- // Last item left
- pQueueTail =
- pQueueHead = 0;
- }
- }
- return pentry;
-}
-
-void WaitConditionImpl::QueueFindAndRemove(EventPoolEntry* pentry)
-{
- // Do an exhaustive search looking for an entry
- EventPoolEntry* p = pQueueHead;
-
- while(p)
- {
- // Entry found? Remove.
- if (p == pentry)
- {
-
- // Remove the node form the list
- // Prev link
- if (pentry->pPrev)
- pentry->pPrev->pNext = pentry->pNext;
- else
- pQueueHead = pentry->pNext;
- // Next link
- if (pentry->pNext)
- pentry->pNext->pPrev = pentry->pPrev;
- else
- pQueueTail = pentry->pPrev;
- // Done
- return;
- }
-
- // Move to next item
- p = p->pNext;
- }
-}
-
-
-bool WaitConditionImpl::Wait(Mutex *pmutex, unsigned delay)
-{
- bool result = 0;
- unsigned i;
- unsigned lockCount = pmutex->pImpl->LockCount;
- EventPoolEntry* pentry;
-
- // Mutex must have been locked
- if (lockCount == 0)
- return 0;
-
- // Add an object to the wait queue
- WaitQueueLoc.DoLock();
- QueuePush(pentry = GetNewEvent());
- WaitQueueLoc.Unlock();
-
- // Finally, release a mutex or semaphore
- if (pmutex->pImpl->Recursive)
- {
- // Release the recursive mutex N times
- pmutex->pImpl->LockCount = 0;
- for(i=0; i<lockCount; i++)
- ::ReleaseMutex(pmutex->pImpl->hMutexOrSemaphore);
- }
- else
- {
- pmutex->pImpl->LockCount = 0;
- ::ReleaseSemaphore(pmutex->pImpl->hMutexOrSemaphore, 1, NULL);
- }
-
- // Note that there is a gap here between mutex.Unlock() and Wait(). However,
- // if notify() comes in at this point in the other thread it will set our
- // corresponding event so wait will just fall through, as expected.
-
- // Block and wait on the event
- DWORD waitResult = ::WaitForSingleObject(pentry->hEvent,
- (delay == OVR_WAIT_INFINITE) ? INFINITE : delay);
- /*
-repeat_wait:
- DWORD waitResult =
-
- ::MsgWaitForMultipleObjects(1, &pentry->hEvent, FALSE,
- (delay == OVR_WAIT_INFINITE) ? INFINITE : delay,
- QS_ALLINPUT);
- */
-
- WaitQueueLoc.DoLock();
- switch(waitResult)
- {
- case WAIT_ABANDONED:
- case WAIT_OBJECT_0:
- result = 1;
- // Wait was successful, therefore the event entry should already be removed
- // So just add entry back to a free list
- ReleaseEvent(pentry);
- break;
- /*
- case WAIT_OBJECT_0 + 1:
- // Messages in WINDOWS queue
- {
- MSG msg;
- PeekMessage(&msg, NULL, 0U, 0U, PM_NOREMOVE);
- WaitQueueLoc.Unlock();
- goto repeat_wait;
- }
- break; */
- default:
- // Timeout, our entry should still be in a queue
- QueueFindAndRemove(pentry);
- ReleaseEvent(pentry);
- }
- WaitQueueLoc.Unlock();
-
- // Re-aquire the mutex
- for(i=0; i<lockCount; i++)
- pmutex->DoLock();
-
- // Return the result
- return result;
-}
-
-// Notify a condition, releasing the least object in a queue
-void WaitConditionImpl::Notify()
-{
- Lock::Locker lock(&WaitQueueLoc);
-
- // Pop last entry & signal it
- EventPoolEntry* pentry = QueuePop();
- if (pentry)
- ::SetEvent(pentry->hEvent);
-}
-
-// Notify a condition, releasing all objects waiting
-void WaitConditionImpl::NotifyAll()
-{
- Lock::Locker lock(&WaitQueueLoc);
-
- // Pop and signal all events
- // NOTE : There is no need to release the events, it's the waiters job to do so
- EventPoolEntry* pentry = QueuePop();
- while (pentry)
- {
- ::SetEvent(pentry->hEvent);
- pentry = QueuePop();
- }
-}
-
-
-
-// *** Actual implementation of WaitCondition
-
-WaitCondition::WaitCondition()
-{
- pImpl = new WaitConditionImpl;
-}
-WaitCondition::~WaitCondition()
-{
- delete pImpl;
-}
-
-// Wait without a mutex
-bool WaitCondition::Wait(Mutex *pmutex, unsigned delay)
-{
- return pImpl->Wait(pmutex, delay);
-}
-// Notification
-void WaitCondition::Notify()
-{
- pImpl->Notify();
-}
-void WaitCondition::NotifyAll()
-{
- pImpl->NotifyAll();
-}
-
-
-
-//-----------------------------------------------------------------------------------
-// ***** Thread Class
-
-// Per-thread variable
-// MA: Don't use TLS for now - portability issues with DLLs, etc.
-/*
-#if !defined(OVR_CC_MSVC) || (OVR_CC_MSVC < 1300)
-__declspec(thread) Thread* pCurrentThread = 0;
-#else
-#pragma data_seg(".tls$")
-__declspec(thread) Thread* pCurrentThread = 0;
-#pragma data_seg(".rwdata")
-#endif
-*/
-
-// *** Thread constructors.
-
-Thread::Thread(UPInt stackSize, int processor)
-{
- CreateParams params;
- params.stackSize = stackSize;
- params.processor = processor;
- Init(params);
-}
-
-Thread::Thread(Thread::ThreadFn threadFunction, void* userHandle, UPInt stackSize,
- int processor, Thread::ThreadState initialState)
-{
- CreateParams params(threadFunction, userHandle, stackSize, processor, initialState);
- Init(params);
-}
-
-Thread::Thread(const CreateParams& params)
-{
- Init(params);
-}
-void Thread::Init(const CreateParams& params)
-{
- // Clear the variables
- ThreadFlags = 0;
- ThreadHandle = 0;
- IdValue = 0;
- ExitCode = 0;
- SuspendCount = 0;
- StackSize = params.stackSize;
- Processor = params.processor;
- Priority = params.priority;
-
- // Clear Function pointers
- ThreadFunction = params.threadFunction;
- UserHandle = params.userHandle;
- if (params.initialState != NotRunning)
- Start(params.initialState);
-
-}
-
-Thread::~Thread()
-{
- // Thread should not running while object is being destroyed,
- // this would indicate ref-counting issue.
- //OVR_ASSERT(IsRunning() == 0);
-
- // Clean up thread.
- CleanupSystemThread();
- ThreadHandle = 0;
-}
-
-
-// *** Overridable User functions.
-
-// Default Run implementation
-int Thread::Run()
-{
- // Call pointer to function, if available.
- return (ThreadFunction) ? ThreadFunction(this, UserHandle) : 0;
-}
-void Thread::OnExit()
-{
-}
-
-// Finishes the thread and releases internal reference to it.
-void Thread::FinishAndRelease()
-{
- // Note: thread must be US.
- ThreadFlags &= (UInt32)~(OVR_THREAD_STARTED);
- ThreadFlags |= OVR_THREAD_FINISHED;
-
- // Release our reference; this is equivalent to 'delete this'
- // from the point of view of our thread.
- Release();
-}
-
-
-// *** ThreadList - used to tack all created threads
-
-class ThreadList : public NewOverrideBase
-{
- //------------------------------------------------------------------------
- struct ThreadHashOp
- {
- UPInt operator()(const Thread* ptr)
- {
- return (((UPInt)ptr) >> 6) ^ (UPInt)ptr;
- }
- };
-
- HashSet<Thread*, ThreadHashOp> ThreadSet;
- Mutex ThreadMutex;
- WaitCondition ThreadsEmpty;
- // Track the root thread that created us.
- ThreadId RootThreadId;
-
- static ThreadList* volatile pRunningThreads;
-
- void addThread(Thread *pthread)
- {
- Mutex::Locker lock(&ThreadMutex);
- ThreadSet.Add(pthread);
- }
-
- void removeThread(Thread *pthread)
- {
- Mutex::Locker lock(&ThreadMutex);
- ThreadSet.Remove(pthread);
- if (ThreadSet.GetSize() == 0)
- ThreadsEmpty.Notify();
- }
-
- void finishAllThreads()
- {
- // Only original root thread can call this.
- OVR_ASSERT(GetCurrentThreadId() == RootThreadId);
-
- Mutex::Locker lock(&ThreadMutex);
- while (ThreadSet.GetSize() != 0)
- ThreadsEmpty.Wait(&ThreadMutex);
- }
-
-public:
-
- ThreadList()
- {
- RootThreadId = GetCurrentThreadId();
- }
- ~ThreadList() { }
-
-
- static void AddRunningThread(Thread *pthread)
- {
- // Non-atomic creation ok since only the root thread
- if (!pRunningThreads)
- {
- pRunningThreads = new ThreadList;
- OVR_ASSERT(pRunningThreads);
- }
- pRunningThreads->addThread(pthread);
- }
-
- // NOTE: 'pthread' might be a dead pointer when this is
- // called so it should not be accessed; it is only used
- // for removal.
- static void RemoveRunningThread(Thread *pthread)
- {
- OVR_ASSERT(pRunningThreads);
- pRunningThreads->removeThread(pthread);
- }
-
- static void FinishAllThreads()
- {
- // This is ok because only root thread can wait for other thread finish.
- if (pRunningThreads)
- {
- pRunningThreads->finishAllThreads();
- delete pRunningThreads;
- pRunningThreads = 0;
- }
- }
-};
-
-// By default, we have no thread list.
-ThreadList* volatile ThreadList::pRunningThreads = 0;
-
-
-// FinishAllThreads - exposed publicly in Thread.
-void Thread::FinishAllThreads()
-{
- ThreadList::FinishAllThreads();
-}
-
-
-// *** Run override
-
-int Thread::PRun()
-{
- // Suspend us on start, if requested
- if (ThreadFlags & OVR_THREAD_START_SUSPENDED)
- {
- Suspend();
- ThreadFlags &= (UInt32)~OVR_THREAD_START_SUSPENDED;
- }
-
- // Call the virtual run function
- ExitCode = Run();
- return ExitCode;
-}
-
-
-
-/* MA: Don't use TLS for now.
-
-// Static function to return a pointer to the current thread
-void Thread::InitCurrentThread(Thread *pthread)
-{
- pCurrentThread = pthread;
-}
-
-// Static function to return a pointer to the current thread
-Thread* Thread::GetThread()
-{
- return pCurrentThread;
-}
-*/
-
-
-// *** User overridables
-
-bool Thread::GetExitFlag() const
-{
- return (ThreadFlags & OVR_THREAD_EXIT) != 0;
-}
-
-void Thread::SetExitFlag(bool exitFlag)
-{
- // The below is atomic since ThreadFlags is AtomicInt.
- if (exitFlag)
- ThreadFlags |= OVR_THREAD_EXIT;
- else
- ThreadFlags &= (UInt32) ~OVR_THREAD_EXIT;
-}
-
-
-// Determines whether the thread was running and is now finished
-bool Thread::IsFinished() const
-{
- return (ThreadFlags & OVR_THREAD_FINISHED) != 0;
-}
-// Determines whether the thread is suspended
-bool Thread::IsSuspended() const
-{
- return SuspendCount > 0;
-}
-// Returns current thread state
-Thread::ThreadState Thread::GetThreadState() const
-{
- if (IsSuspended())
- return Suspended;
- if (ThreadFlags & OVR_THREAD_STARTED)
- return Running;
- return NotRunning;
-}
-
-
-
-// ***** Thread management
-/* static */
-int Thread::GetOSPriority(ThreadPriority p)
-{
- switch(p)
- {
- case Thread::CriticalPriority: return THREAD_PRIORITY_TIME_CRITICAL;
- case Thread::HighestPriority: return THREAD_PRIORITY_HIGHEST;
- case Thread::AboveNormalPriority: return THREAD_PRIORITY_ABOVE_NORMAL;
- case Thread::NormalPriority: return THREAD_PRIORITY_NORMAL;
- case Thread::BelowNormalPriority: return THREAD_PRIORITY_BELOW_NORMAL;
- case Thread::LowestPriority: return THREAD_PRIORITY_LOWEST;
- case Thread::IdlePriority: return THREAD_PRIORITY_IDLE;
- }
- return THREAD_PRIORITY_NORMAL;
-}
-
-// The actual first function called on thread start
-unsigned WINAPI Thread_Win32StartFn(void * phandle)
-{
- Thread * pthread = (Thread*)phandle;
- if (pthread->Processor != -1)
- {
- DWORD_PTR ret = SetThreadAffinityMask(GetCurrentThread(), (DWORD)pthread->Processor);
- if (ret == 0)
- OVR_DEBUG_LOG(("Could not set hardware processor for the thread"));
- }
- BOOL ret = ::SetThreadPriority(GetCurrentThread(), Thread::GetOSPriority(pthread->Priority));
- if (ret == 0)
- OVR_DEBUG_LOG(("Could not set thread priority"));
- OVR_UNUSED(ret);
-
- // Ensure that ThreadId is assigned once thread is running, in case
- // beginthread hasn't filled it in yet.
- pthread->IdValue = (ThreadId)::GetCurrentThreadId();
-
- DWORD result = pthread->PRun();
- // Signal the thread as done and release it atomically.
- pthread->FinishAndRelease();
- // At this point Thread object might be dead; however we can still pass
- // it to RemoveRunningThread since it is only used as a key there.
- ThreadList::RemoveRunningThread(pthread);
- return (unsigned) result;
-}
-
-bool Thread::Start(ThreadState initialState)
-{
- if (initialState == NotRunning)
- return 0;
- if (GetThreadState() != NotRunning)
- {
- OVR_DEBUG_LOG(("Thread::Start failed - thread %p already running", this));
- return 0;
- }
-
- // Free old thread handle before creating the new one
- CleanupSystemThread();
-
- // AddRef to us until the thread is finished.
- AddRef();
- ThreadList::AddRunningThread(this);
-
- ExitCode = 0;
- SuspendCount = 0;
- ThreadFlags = (initialState == Running) ? 0 : OVR_THREAD_START_SUSPENDED;
- ThreadHandle = (HANDLE) _beginthreadex(0, (unsigned)StackSize,
- Thread_Win32StartFn, this, 0, (unsigned*)&IdValue);
-
- // Failed? Fail the function
- if (ThreadHandle == 0)
- {
- ThreadFlags = 0;
- Release();
- ThreadList::RemoveRunningThread(this);
- return 0;
- }
- return 1;
-}
-
-
-// Suspend the thread until resumed
-bool Thread::Suspend()
-{
- // Can't suspend a thread that wasn't started
- if (!(ThreadFlags & OVR_THREAD_STARTED))
- return 0;
-
- if (::SuspendThread(ThreadHandle) != 0xFFFFFFFF)
- {
- SuspendCount++;
- return 1;
- }
- return 0;
-}
-
-// Resumes currently suspended thread
-bool Thread::Resume()
-{
- // Can't suspend a thread that wasn't started
- if (!(ThreadFlags & OVR_THREAD_STARTED))
- return 0;
-
- // Decrement count, and resume thread if it is 0
- SInt32 oldCount = SuspendCount.ExchangeAdd_Acquire(-1);
- if (oldCount >= 1)
- {
- if (oldCount == 1)
- {
- if (::ResumeThread(ThreadHandle) != 0xFFFFFFFF)
- return 1;
- }
- else
- {
- return 1;
- }
- }
- return 0;
-}
-
-
-// Quits with an exit code
-void Thread::Exit(int exitCode)
-{
- // Can only exist the current thread.
- // MA: Don't use TLS for now.
- //if (GetThread() != this)
- // return;
-
- // Call the virtual OnExit function.
- OnExit();
-
- // Signal this thread object as done and release it's references.
- FinishAndRelease();
- ThreadList::RemoveRunningThread(this);
-
- // Call the exit function.
- _endthreadex((unsigned)exitCode);
-}
-
-
-void Thread::CleanupSystemThread()
-{
- if (ThreadHandle != 0)
- {
- ::CloseHandle(ThreadHandle);
- ThreadHandle = 0;
- }
-}
-
-// *** Sleep functions
-// static
-bool Thread::Sleep(unsigned secs)
-{
- ::Sleep(secs*1000);
- return 1;
-}
-
-// static
-bool Thread::MSleep(unsigned msecs)
-{
- ::Sleep(msecs);
- return 1;
-}
-
-void Thread::SetThreadName( const char* name )
-{
-#if !defined(OVR_BUILD_SHIPPING) || defined(OVR_BUILD_PROFILING)
- // Looks ugly, but it is the recommended way to name a thread.
- typedef struct tagTHREADNAME_INFO {
- DWORD dwType; // Must be 0x1000
- LPCSTR szName; // Pointer to name (in user address space)
- DWORD dwThreadID; // Thread ID (-1 for caller thread)
- DWORD dwFlags; // Reserved for future use; must be zero
- } THREADNAME_INFO;
-
- THREADNAME_INFO info;
-
- info.dwType = 0x1000;
- info.szName = name;
- info.dwThreadID = reinterpret_cast<DWORD>(GetThreadId());
- info.dwFlags = 0;
-
- __try
- {
-#ifdef _WIN64
- RaiseException( 0x406D1388, 0, sizeof(info)/sizeof(DWORD), (const ULONG_PTR *)&info );
-#else
- RaiseException( 0x406D1388, 0, sizeof(info)/sizeof(DWORD), (DWORD *)&info );
-#endif
- }
- __except( GetExceptionCode()==0x406D1388 ? EXCEPTION_CONTINUE_EXECUTION : EXCEPTION_EXECUTE_HANDLER )
- {
- }
-#endif // OVR_BUILD_SHIPPING
-}
-
-// static
-int Thread::GetCPUCount()
-{
- SYSTEM_INFO sysInfo;
- GetSystemInfo(&sysInfo);
- return (int) sysInfo.dwNumberOfProcessors;
-}
-
-// Returns the unique Id of a thread it is called on, intended for
-// comparison purposes.
-ThreadId GetCurrentThreadId()
-{
- return (ThreadId)::GetCurrentThreadId();
-}
-
-} // OVR
-
-#endif
-
-
+/************************************************************************************
+
+Filename : OVR_ThreadsWinAPI.cpp
+Platform : WinAPI
+Content : Windows specific thread-related (safe) functionality
+Created : September 19, 2012
+Notes :
+
+Copyright : Copyright 2012 Oculus VR, Inc. All Rights reserved.
+
+Use of this software is subject to the terms of the Oculus license
+agreement provided at the time of installation or download, or which
+otherwise accompanies this software in either electronic or hard copy form.
+
+************************************************************************************/
+
+#include "OVR_Threads.h"
+#include "OVR_Hash.h"
+#include "OVR_Log.h"
+
+#ifdef OVR_ENABLE_THREADS
+
+// For _beginthreadex / _endtheadex
+#include <process.h>
+
+namespace OVR {
+
+
+//-----------------------------------------------------------------------------------
+// *** Internal Mutex implementation class
+
+class MutexImpl : public NewOverrideBase
+{
+ // System mutex or semaphore
+ HANDLE hMutexOrSemaphore;
+ bool Recursive;
+ volatile unsigned LockCount;
+
+ friend class WaitConditionImpl;
+
+public:
+ // Constructor/destructor
+ MutexImpl(bool recursive = 1);
+ ~MutexImpl();
+
+ // Locking functions
+ void DoLock();
+ bool TryLock();
+ void Unlock(Mutex* pmutex);
+ // Returns 1 if the mutes is currently locked
+ bool IsLockedByAnotherThread(Mutex* pmutex);
+};
+
+// *** Constructor/destructor
+MutexImpl::MutexImpl(bool recursive)
+{
+ Recursive = recursive;
+ LockCount = 0;
+ hMutexOrSemaphore = Recursive ? CreateMutex(NULL, 0, NULL) : CreateSemaphore(NULL, 1, 1, NULL);
+}
+MutexImpl::~MutexImpl()
+{
+ CloseHandle(hMutexOrSemaphore);
+}
+
+
+// Lock and try lock
+void MutexImpl::DoLock()
+{
+ if (::WaitForSingleObject(hMutexOrSemaphore, INFINITE) != WAIT_OBJECT_0)
+ return;
+ LockCount++;
+}
+
+bool MutexImpl::TryLock()
+{
+ DWORD ret;
+ if ((ret=::WaitForSingleObject(hMutexOrSemaphore, 0)) != WAIT_OBJECT_0)
+ return 0;
+ LockCount++;
+ return 1;
+}
+
+void MutexImpl::Unlock(Mutex* pmutex)
+{
+ OVR_UNUSED(pmutex);
+
+ unsigned lockCount;
+ LockCount--;
+ lockCount = LockCount;
+
+ // Release mutex
+ if ((Recursive ? ReleaseMutex(hMutexOrSemaphore) :
+ ReleaseSemaphore(hMutexOrSemaphore, 1, NULL)) != 0)
+ {
+ // This used to call Wait handlers if lockCount == 0.
+ }
+}
+
+bool MutexImpl::IsLockedByAnotherThread(Mutex* pmutex)
+{
+ // There could be multiple interpretations of IsLocked with respect to current thread
+ if (LockCount == 0)
+ return 0;
+ if (!TryLock())
+ return 1;
+ Unlock(pmutex);
+ return 0;
+}
+
+/*
+bool MutexImpl::IsSignaled() const
+{
+ // An mutex is signaled if it is not locked ANYWHERE
+ // Note that this is different from IsLockedByAnotherThread function,
+ // that takes current thread into account
+ return LockCount == 0;
+}
+*/
+
+
+// *** Actual Mutex class implementation
+
+Mutex::Mutex(bool recursive)
+{
+ pImpl = new MutexImpl(recursive);
+}
+Mutex::~Mutex()
+{
+ delete pImpl;
+}
+
+// Lock and try lock
+void Mutex::DoLock()
+{
+ pImpl->DoLock();
+}
+bool Mutex::TryLock()
+{
+ return pImpl->TryLock();
+}
+void Mutex::Unlock()
+{
+ pImpl->Unlock(this);
+}
+bool Mutex::IsLockedByAnotherThread()
+{
+ return pImpl->IsLockedByAnotherThread(this);
+}
+
+//-----------------------------------------------------------------------------------
+// ***** Event
+
+bool Event::Wait(unsigned delay)
+{
+ Mutex::Locker lock(&StateMutex);
+
+ // Do the correct amount of waiting
+ if (delay == OVR_WAIT_INFINITE)
+ {
+ while(!State)
+ StateWaitCondition.Wait(&StateMutex);
+ }
+ else if (delay)
+ {
+ if (!State)
+ StateWaitCondition.Wait(&StateMutex, delay);
+ }
+
+ bool state = State;
+ // Take care of temporary 'pulsing' of a state
+ if (Temporary)
+ {
+ Temporary = false;
+ State = false;
+ }
+ return state;
+}
+
+void Event::updateState(bool newState, bool newTemp, bool mustNotify)
+{
+ Mutex::Locker lock(&StateMutex);
+ State = newState;
+ Temporary = newTemp;
+ if (mustNotify)
+ StateWaitCondition.NotifyAll();
+}
+
+
+//-----------------------------------------------------------------------------------
+// ***** Win32 Wait Condition Implementation
+
+// Internal implementation class
+class WaitConditionImpl : public NewOverrideBase
+{
+ // Event pool entries for extra events
+ struct EventPoolEntry : public NewOverrideBase
+ {
+ HANDLE hEvent;
+ EventPoolEntry *pNext;
+ EventPoolEntry *pPrev;
+ };
+
+ Lock WaitQueueLoc;
+ // Stores free events that can be used later
+ EventPoolEntry * pFreeEventList;
+
+ // A queue of waiting objects to be signaled
+ EventPoolEntry* pQueueHead;
+ EventPoolEntry* pQueueTail;
+
+ // Allocation functions for free events
+ EventPoolEntry* GetNewEvent();
+ void ReleaseEvent(EventPoolEntry* pevent);
+
+ // Queue operations
+ void QueuePush(EventPoolEntry* pentry);
+ EventPoolEntry* QueuePop();
+ void QueueFindAndRemove(EventPoolEntry* pentry);
+
+public:
+
+ // Constructor/destructor
+ WaitConditionImpl();
+ ~WaitConditionImpl();
+
+ // Release mutex and wait for condition. The mutex is re-acqured after the wait.
+ bool Wait(Mutex *pmutex, unsigned delay = OVR_WAIT_INFINITE);
+
+ // Notify a condition, releasing at one object waiting
+ void Notify();
+ // Notify a condition, releasing all objects waiting
+ void NotifyAll();
+};
+
+
+
+WaitConditionImpl::WaitConditionImpl()
+{
+ pFreeEventList = 0;
+ pQueueHead =
+ pQueueTail = 0;
+}
+
+WaitConditionImpl::~WaitConditionImpl()
+{
+ // Free all the resources
+ EventPoolEntry* p = pFreeEventList;
+ EventPoolEntry* pentry;
+
+ while(p)
+ {
+ // Move to next
+ pentry = p;
+ p = p->pNext;
+ // Delete old
+ ::CloseHandle(pentry->hEvent);
+ delete pentry;
+ }
+ // Shouldn't we also consider the queue?
+
+ // To be safe
+ pFreeEventList = 0;
+ pQueueHead =
+ pQueueTail = 0;
+}
+
+
+// Allocation functions for free events
+WaitConditionImpl::EventPoolEntry* WaitConditionImpl::GetNewEvent()
+{
+ EventPoolEntry* pentry;
+
+ // If there are any free nodes, use them
+ if (pFreeEventList)
+ {
+ pentry = pFreeEventList;
+ pFreeEventList = pFreeEventList->pNext;
+ }
+ else
+ {
+ // Allocate a new node
+ pentry = new EventPoolEntry;
+ pentry->pNext = 0;
+ pentry->pPrev = 0;
+ // Non-signaled manual event
+ pentry->hEvent = ::CreateEvent(NULL, TRUE, 0, NULL);
+ }
+
+ return pentry;
+}
+
+void WaitConditionImpl::ReleaseEvent(EventPoolEntry* pevent)
+{
+ // Mark event as non-signaled
+ ::ResetEvent(pevent->hEvent);
+ // And add it to free pool
+ pevent->pNext = pFreeEventList;
+ pevent->pPrev = 0;
+ pFreeEventList = pevent;
+}
+
+// Queue operations
+void WaitConditionImpl::QueuePush(EventPoolEntry* pentry)
+{
+ // Items already exist? Just add to tail
+ if (pQueueTail)
+ {
+ pentry->pPrev = pQueueTail;
+ pQueueTail->pNext = pentry;
+ pentry->pNext = 0;
+ pQueueTail = pentry;
+ }
+ else
+ {
+ // No items in queue
+ pentry->pNext =
+ pentry->pPrev = 0;
+ pQueueHead =
+ pQueueTail = pentry;
+ }
+}
+
+WaitConditionImpl::EventPoolEntry* WaitConditionImpl::QueuePop()
+{
+ EventPoolEntry* pentry = pQueueHead;
+
+ // No items, null pointer
+ if (pentry)
+ {
+ // More items after this one? just grab the first item
+ if (pQueueHead->pNext)
+ {
+ pQueueHead = pentry->pNext;
+ pQueueHead->pPrev = 0;
+ }
+ else
+ {
+ // Last item left
+ pQueueTail =
+ pQueueHead = 0;
+ }
+ }
+ return pentry;
+}
+
+void WaitConditionImpl::QueueFindAndRemove(EventPoolEntry* pentry)
+{
+ // Do an exhaustive search looking for an entry
+ EventPoolEntry* p = pQueueHead;
+
+ while(p)
+ {
+ // Entry found? Remove.
+ if (p == pentry)
+ {
+
+ // Remove the node form the list
+ // Prev link
+ if (pentry->pPrev)
+ pentry->pPrev->pNext = pentry->pNext;
+ else
+ pQueueHead = pentry->pNext;
+ // Next link
+ if (pentry->pNext)
+ pentry->pNext->pPrev = pentry->pPrev;
+ else
+ pQueueTail = pentry->pPrev;
+ // Done
+ return;
+ }
+
+ // Move to next item
+ p = p->pNext;
+ }
+}
+
+
+bool WaitConditionImpl::Wait(Mutex *pmutex, unsigned delay)
+{
+ bool result = 0;
+ unsigned i;
+ unsigned lockCount = pmutex->pImpl->LockCount;
+ EventPoolEntry* pentry;
+
+ // Mutex must have been locked
+ if (lockCount == 0)
+ return 0;
+
+ // Add an object to the wait queue
+ WaitQueueLoc.DoLock();
+ QueuePush(pentry = GetNewEvent());
+ WaitQueueLoc.Unlock();
+
+ // Finally, release a mutex or semaphore
+ if (pmutex->pImpl->Recursive)
+ {
+ // Release the recursive mutex N times
+ pmutex->pImpl->LockCount = 0;
+ for(i=0; i<lockCount; i++)
+ ::ReleaseMutex(pmutex->pImpl->hMutexOrSemaphore);
+ }
+ else
+ {
+ pmutex->pImpl->LockCount = 0;
+ ::ReleaseSemaphore(pmutex->pImpl->hMutexOrSemaphore, 1, NULL);
+ }
+
+ // Note that there is a gap here between mutex.Unlock() and Wait(). However,
+ // if notify() comes in at this point in the other thread it will set our
+ // corresponding event so wait will just fall through, as expected.
+
+ // Block and wait on the event
+ DWORD waitResult = ::WaitForSingleObject(pentry->hEvent,
+ (delay == OVR_WAIT_INFINITE) ? INFINITE : delay);
+ /*
+repeat_wait:
+ DWORD waitResult =
+
+ ::MsgWaitForMultipleObjects(1, &pentry->hEvent, FALSE,
+ (delay == OVR_WAIT_INFINITE) ? INFINITE : delay,
+ QS_ALLINPUT);
+ */
+
+ WaitQueueLoc.DoLock();
+ switch(waitResult)
+ {
+ case WAIT_ABANDONED:
+ case WAIT_OBJECT_0:
+ result = 1;
+ // Wait was successful, therefore the event entry should already be removed
+ // So just add entry back to a free list
+ ReleaseEvent(pentry);
+ break;
+ /*
+ case WAIT_OBJECT_0 + 1:
+ // Messages in WINDOWS queue
+ {
+ MSG msg;
+ PeekMessage(&msg, NULL, 0U, 0U, PM_NOREMOVE);
+ WaitQueueLoc.Unlock();
+ goto repeat_wait;
+ }
+ break; */
+ default:
+ // Timeout, our entry should still be in a queue
+ QueueFindAndRemove(pentry);
+ ReleaseEvent(pentry);
+ }
+ WaitQueueLoc.Unlock();
+
+ // Re-aquire the mutex
+ for(i=0; i<lockCount; i++)
+ pmutex->DoLock();
+
+ // Return the result
+ return result;
+}
+
+// Notify a condition, releasing the least object in a queue
+void WaitConditionImpl::Notify()
+{
+ Lock::Locker lock(&WaitQueueLoc);
+
+ // Pop last entry & signal it
+ EventPoolEntry* pentry = QueuePop();
+ if (pentry)
+ ::SetEvent(pentry->hEvent);
+}
+
+// Notify a condition, releasing all objects waiting
+void WaitConditionImpl::NotifyAll()
+{
+ Lock::Locker lock(&WaitQueueLoc);
+
+ // Pop and signal all events
+ // NOTE : There is no need to release the events, it's the waiters job to do so
+ EventPoolEntry* pentry = QueuePop();
+ while (pentry)
+ {
+ ::SetEvent(pentry->hEvent);
+ pentry = QueuePop();
+ }
+}
+
+
+
+// *** Actual implementation of WaitCondition
+
+WaitCondition::WaitCondition()
+{
+ pImpl = new WaitConditionImpl;
+}
+WaitCondition::~WaitCondition()
+{
+ delete pImpl;
+}
+
+// Wait without a mutex
+bool WaitCondition::Wait(Mutex *pmutex, unsigned delay)
+{
+ return pImpl->Wait(pmutex, delay);
+}
+// Notification
+void WaitCondition::Notify()
+{
+ pImpl->Notify();
+}
+void WaitCondition::NotifyAll()
+{
+ pImpl->NotifyAll();
+}
+
+
+
+//-----------------------------------------------------------------------------------
+// ***** Thread Class
+
+// Per-thread variable
+// MA: Don't use TLS for now - portability issues with DLLs, etc.
+/*
+#if !defined(OVR_CC_MSVC) || (OVR_CC_MSVC < 1300)
+__declspec(thread) Thread* pCurrentThread = 0;
+#else
+#pragma data_seg(".tls$")
+__declspec(thread) Thread* pCurrentThread = 0;
+#pragma data_seg(".rwdata")
+#endif
+*/
+
+// *** Thread constructors.
+
+Thread::Thread(UPInt stackSize, int processor)
+{
+ CreateParams params;
+ params.stackSize = stackSize;
+ params.processor = processor;
+ Init(params);
+}
+
+Thread::Thread(Thread::ThreadFn threadFunction, void* userHandle, UPInt stackSize,
+ int processor, Thread::ThreadState initialState)
+{
+ CreateParams params(threadFunction, userHandle, stackSize, processor, initialState);
+ Init(params);
+}
+
+Thread::Thread(const CreateParams& params)
+{
+ Init(params);
+}
+void Thread::Init(const CreateParams& params)
+{
+ // Clear the variables
+ ThreadFlags = 0;
+ ThreadHandle = 0;
+ IdValue = 0;
+ ExitCode = 0;
+ SuspendCount = 0;
+ StackSize = params.stackSize;
+ Processor = params.processor;
+ Priority = params.priority;
+
+ // Clear Function pointers
+ ThreadFunction = params.threadFunction;
+ UserHandle = params.userHandle;
+ if (params.initialState != NotRunning)
+ Start(params.initialState);
+
+}
+
+Thread::~Thread()
+{
+ // Thread should not running while object is being destroyed,
+ // this would indicate ref-counting issue.
+ //OVR_ASSERT(IsRunning() == 0);
+
+ // Clean up thread.
+ CleanupSystemThread();
+ ThreadHandle = 0;
+}
+
+
+// *** Overridable User functions.
+
+// Default Run implementation
+int Thread::Run()
+{
+ // Call pointer to function, if available.
+ return (ThreadFunction) ? ThreadFunction(this, UserHandle) : 0;
+}
+void Thread::OnExit()
+{
+}
+
+// Finishes the thread and releases internal reference to it.
+void Thread::FinishAndRelease()
+{
+ // Note: thread must be US.
+ ThreadFlags &= (UInt32)~(OVR_THREAD_STARTED);
+ ThreadFlags |= OVR_THREAD_FINISHED;
+
+ // Release our reference; this is equivalent to 'delete this'
+ // from the point of view of our thread.
+ Release();
+}
+
+
+// *** ThreadList - used to tack all created threads
+
+class ThreadList : public NewOverrideBase
+{
+ //------------------------------------------------------------------------
+ struct ThreadHashOp
+ {
+ UPInt operator()(const Thread* ptr)
+ {
+ return (((UPInt)ptr) >> 6) ^ (UPInt)ptr;
+ }
+ };
+
+ HashSet<Thread*, ThreadHashOp> ThreadSet;
+ Mutex ThreadMutex;
+ WaitCondition ThreadsEmpty;
+ // Track the root thread that created us.
+ ThreadId RootThreadId;
+
+ static ThreadList* volatile pRunningThreads;
+
+ void addThread(Thread *pthread)
+ {
+ Mutex::Locker lock(&ThreadMutex);
+ ThreadSet.Add(pthread);
+ }
+
+ void removeThread(Thread *pthread)
+ {
+ Mutex::Locker lock(&ThreadMutex);
+ ThreadSet.Remove(pthread);
+ if (ThreadSet.GetSize() == 0)
+ ThreadsEmpty.Notify();
+ }
+
+ void finishAllThreads()
+ {
+ // Only original root thread can call this.
+ OVR_ASSERT(GetCurrentThreadId() == RootThreadId);
+
+ Mutex::Locker lock(&ThreadMutex);
+ while (ThreadSet.GetSize() != 0)
+ ThreadsEmpty.Wait(&ThreadMutex);
+ }
+
+public:
+
+ ThreadList()
+ {
+ RootThreadId = GetCurrentThreadId();
+ }
+ ~ThreadList() { }
+
+
+ static void AddRunningThread(Thread *pthread)
+ {
+ // Non-atomic creation ok since only the root thread
+ if (!pRunningThreads)
+ {
+ pRunningThreads = new ThreadList;
+ OVR_ASSERT(pRunningThreads);
+ }
+ pRunningThreads->addThread(pthread);
+ }
+
+ // NOTE: 'pthread' might be a dead pointer when this is
+ // called so it should not be accessed; it is only used
+ // for removal.
+ static void RemoveRunningThread(Thread *pthread)
+ {
+ OVR_ASSERT(pRunningThreads);
+ pRunningThreads->removeThread(pthread);
+ }
+
+ static void FinishAllThreads()
+ {
+ // This is ok because only root thread can wait for other thread finish.
+ if (pRunningThreads)
+ {
+ pRunningThreads->finishAllThreads();
+ delete pRunningThreads;
+ pRunningThreads = 0;
+ }
+ }
+};
+
+// By default, we have no thread list.
+ThreadList* volatile ThreadList::pRunningThreads = 0;
+
+
+// FinishAllThreads - exposed publicly in Thread.
+void Thread::FinishAllThreads()
+{
+ ThreadList::FinishAllThreads();
+}
+
+
+// *** Run override
+
+int Thread::PRun()
+{
+ // Suspend us on start, if requested
+ if (ThreadFlags & OVR_THREAD_START_SUSPENDED)
+ {
+ Suspend();
+ ThreadFlags &= (UInt32)~OVR_THREAD_START_SUSPENDED;
+ }
+
+ // Call the virtual run function
+ ExitCode = Run();
+ return ExitCode;
+}
+
+
+
+/* MA: Don't use TLS for now.
+
+// Static function to return a pointer to the current thread
+void Thread::InitCurrentThread(Thread *pthread)
+{
+ pCurrentThread = pthread;
+}
+
+// Static function to return a pointer to the current thread
+Thread* Thread::GetThread()
+{
+ return pCurrentThread;
+}
+*/
+
+
+// *** User overridables
+
+bool Thread::GetExitFlag() const
+{
+ return (ThreadFlags & OVR_THREAD_EXIT) != 0;
+}
+
+void Thread::SetExitFlag(bool exitFlag)
+{
+ // The below is atomic since ThreadFlags is AtomicInt.
+ if (exitFlag)
+ ThreadFlags |= OVR_THREAD_EXIT;
+ else
+ ThreadFlags &= (UInt32) ~OVR_THREAD_EXIT;
+}
+
+
+// Determines whether the thread was running and is now finished
+bool Thread::IsFinished() const
+{
+ return (ThreadFlags & OVR_THREAD_FINISHED) != 0;
+}
+// Determines whether the thread is suspended
+bool Thread::IsSuspended() const
+{
+ return SuspendCount > 0;
+}
+// Returns current thread state
+Thread::ThreadState Thread::GetThreadState() const
+{
+ if (IsSuspended())
+ return Suspended;
+ if (ThreadFlags & OVR_THREAD_STARTED)
+ return Running;
+ return NotRunning;
+}
+
+
+
+// ***** Thread management
+/* static */
+int Thread::GetOSPriority(ThreadPriority p)
+{
+ switch(p)
+ {
+ case Thread::CriticalPriority: return THREAD_PRIORITY_TIME_CRITICAL;
+ case Thread::HighestPriority: return THREAD_PRIORITY_HIGHEST;
+ case Thread::AboveNormalPriority: return THREAD_PRIORITY_ABOVE_NORMAL;
+ case Thread::NormalPriority: return THREAD_PRIORITY_NORMAL;
+ case Thread::BelowNormalPriority: return THREAD_PRIORITY_BELOW_NORMAL;
+ case Thread::LowestPriority: return THREAD_PRIORITY_LOWEST;
+ case Thread::IdlePriority: return THREAD_PRIORITY_IDLE;
+ }
+ return THREAD_PRIORITY_NORMAL;
+}
+
+// The actual first function called on thread start
+unsigned WINAPI Thread_Win32StartFn(void * phandle)
+{
+ Thread * pthread = (Thread*)phandle;
+ if (pthread->Processor != -1)
+ {
+ DWORD_PTR ret = SetThreadAffinityMask(GetCurrentThread(), (DWORD)pthread->Processor);
+ if (ret == 0)
+ OVR_DEBUG_LOG(("Could not set hardware processor for the thread"));
+ }
+ BOOL ret = ::SetThreadPriority(GetCurrentThread(), Thread::GetOSPriority(pthread->Priority));
+ if (ret == 0)
+ OVR_DEBUG_LOG(("Could not set thread priority"));
+ OVR_UNUSED(ret);
+
+ // Ensure that ThreadId is assigned once thread is running, in case
+ // beginthread hasn't filled it in yet.
+ pthread->IdValue = (ThreadId)::GetCurrentThreadId();
+
+ DWORD result = pthread->PRun();
+ // Signal the thread as done and release it atomically.
+ pthread->FinishAndRelease();
+ // At this point Thread object might be dead; however we can still pass
+ // it to RemoveRunningThread since it is only used as a key there.
+ ThreadList::RemoveRunningThread(pthread);
+ return (unsigned) result;
+}
+
+bool Thread::Start(ThreadState initialState)
+{
+ if (initialState == NotRunning)
+ return 0;
+ if (GetThreadState() != NotRunning)
+ {
+ OVR_DEBUG_LOG(("Thread::Start failed - thread %p already running", this));
+ return 0;
+ }
+
+ // Free old thread handle before creating the new one
+ CleanupSystemThread();
+
+ // AddRef to us until the thread is finished.
+ AddRef();
+ ThreadList::AddRunningThread(this);
+
+ ExitCode = 0;
+ SuspendCount = 0;
+ ThreadFlags = (initialState == Running) ? 0 : OVR_THREAD_START_SUSPENDED;
+ ThreadHandle = (HANDLE) _beginthreadex(0, (unsigned)StackSize,
+ Thread_Win32StartFn, this, 0, (unsigned*)&IdValue);
+
+ // Failed? Fail the function
+ if (ThreadHandle == 0)
+ {
+ ThreadFlags = 0;
+ Release();
+ ThreadList::RemoveRunningThread(this);
+ return 0;
+ }
+ return 1;
+}
+
+
+// Suspend the thread until resumed
+bool Thread::Suspend()
+{
+ // Can't suspend a thread that wasn't started
+ if (!(ThreadFlags & OVR_THREAD_STARTED))
+ return 0;
+
+ if (::SuspendThread(ThreadHandle) != 0xFFFFFFFF)
+ {
+ SuspendCount++;
+ return 1;
+ }
+ return 0;
+}
+
+// Resumes currently suspended thread
+bool Thread::Resume()
+{
+ // Can't suspend a thread that wasn't started
+ if (!(ThreadFlags & OVR_THREAD_STARTED))
+ return 0;
+
+ // Decrement count, and resume thread if it is 0
+ SInt32 oldCount = SuspendCount.ExchangeAdd_Acquire(-1);
+ if (oldCount >= 1)
+ {
+ if (oldCount == 1)
+ {
+ if (::ResumeThread(ThreadHandle) != 0xFFFFFFFF)
+ return 1;
+ }
+ else
+ {
+ return 1;
+ }
+ }
+ return 0;
+}
+
+
+// Quits with an exit code
+void Thread::Exit(int exitCode)
+{
+ // Can only exist the current thread.
+ // MA: Don't use TLS for now.
+ //if (GetThread() != this)
+ // return;
+
+ // Call the virtual OnExit function.
+ OnExit();
+
+ // Signal this thread object as done and release it's references.
+ FinishAndRelease();
+ ThreadList::RemoveRunningThread(this);
+
+ // Call the exit function.
+ _endthreadex((unsigned)exitCode);
+}
+
+
+void Thread::CleanupSystemThread()
+{
+ if (ThreadHandle != 0)
+ {
+ ::CloseHandle(ThreadHandle);
+ ThreadHandle = 0;
+ }
+}
+
+// *** Sleep functions
+// static
+bool Thread::Sleep(unsigned secs)
+{
+ ::Sleep(secs*1000);
+ return 1;
+}
+
+// static
+bool Thread::MSleep(unsigned msecs)
+{
+ ::Sleep(msecs);
+ return 1;
+}
+
+void Thread::SetThreadName( const char* name )
+{
+#if !defined(OVR_BUILD_SHIPPING) || defined(OVR_BUILD_PROFILING)
+ // Looks ugly, but it is the recommended way to name a thread.
+ typedef struct tagTHREADNAME_INFO {
+ DWORD dwType; // Must be 0x1000
+ LPCSTR szName; // Pointer to name (in user address space)
+ DWORD dwThreadID; // Thread ID (-1 for caller thread)
+ DWORD dwFlags; // Reserved for future use; must be zero
+ } THREADNAME_INFO;
+
+ THREADNAME_INFO info;
+
+ info.dwType = 0x1000;
+ info.szName = name;
+ info.dwThreadID = reinterpret_cast<DWORD>(GetThreadId());
+ info.dwFlags = 0;
+
+ __try
+ {
+#ifdef _WIN64
+ RaiseException( 0x406D1388, 0, sizeof(info)/sizeof(DWORD), (const ULONG_PTR *)&info );
+#else
+ RaiseException( 0x406D1388, 0, sizeof(info)/sizeof(DWORD), (DWORD *)&info );
+#endif
+ }
+ __except( GetExceptionCode()==0x406D1388 ? EXCEPTION_CONTINUE_EXECUTION : EXCEPTION_EXECUTE_HANDLER )
+ {
+ }
+#endif // OVR_BUILD_SHIPPING
+}
+
+// static
+int Thread::GetCPUCount()
+{
+ SYSTEM_INFO sysInfo;
+ GetSystemInfo(&sysInfo);
+ return (int) sysInfo.dwNumberOfProcessors;
+}
+
+// Returns the unique Id of a thread it is called on, intended for
+// comparison purposes.
+ThreadId GetCurrentThreadId()
+{
+ return (ThreadId)::GetCurrentThreadId();
+}
+
+} // OVR
+
+#endif
+
+
diff --git a/LibOVR/Src/Kernel/OVR_Timer.cpp b/LibOVR/Src/Kernel/OVR_Timer.cpp
index db25b8f..682d621 100644
--- a/LibOVR/Src/Kernel/OVR_Timer.cpp
+++ b/LibOVR/Src/Kernel/OVR_Timer.cpp
@@ -1,156 +1,156 @@
-/************************************************************************************
-
-Filename : OVR_Timer.cpp
-Content : Provides static functions for precise timing
-Created : September 19, 2012
-Notes :
-
-Copyright : Copyright 2012 Oculus VR, Inc. All Rights reserved.
-
-Use of this software is subject to the terms of the Oculus license
-agreement provided at the time of installation or download, or which
-otherwise accompanies this software in either electronic or hard copy form.
-
-************************************************************************************/
-
-#include "OVR_Timer.h"
-
-#if defined (OVR_OS_WIN32)
-#include <windows.h>
-
-#else
-#include <sys/time.h>
-#endif
-
-namespace OVR {
-
-//-----------------------------------------------------------------------------------
-// ***** Timer Class
-
-UInt64 Timer::GetProfileTicks()
-{
- return (GetRawTicks() * MksPerSecond) / GetRawFrequency();
-}
-double Timer::GetProfileSeconds()
-{
- static UInt64 StartTime = GetProfileTicks();
- return TicksToSeconds(GetProfileTicks()-StartTime);
-}
-
-
-//------------------------------------------------------------------------
-// *** Win32 Specific Timer
-
-#if (defined (OVR_OS_WIN32))
-
-CRITICAL_SECTION WinAPI_GetTimeCS;
-volatile UInt32 WinAPI_OldTime = 0;
-volatile UInt32 WinAPI_WrapCounter = 0;
-
-
-UInt32 Timer::GetTicksMs()
-{
- return timeGetTime();
-}
-
-UInt64 Timer::GetTicks()
-{
- DWORD ticks = timeGetTime();
- UInt64 result;
-
- // On Win32 QueryPerformanceFrequency is unreliable due to SMP and
- // performance levels, so use this logic to detect wrapping and track
- // high bits.
- ::EnterCriticalSection(&WinAPI_GetTimeCS);
-
- if (WinAPI_OldTime > ticks)
- WinAPI_WrapCounter++;
- WinAPI_OldTime = ticks;
-
- result = (UInt64(WinAPI_WrapCounter) << 32) | ticks;
- ::LeaveCriticalSection(&WinAPI_GetTimeCS);
-
- return result * MksPerMs;
-}
-
-UInt64 Timer::GetRawTicks()
-{
- LARGE_INTEGER li;
- QueryPerformanceCounter(&li);
- return li.QuadPart;
-}
-
-UInt64 Timer::GetRawFrequency()
-{
- static UInt64 perfFreq = 0;
- if (perfFreq == 0)
- {
- LARGE_INTEGER freq;
- QueryPerformanceFrequency(&freq);
- perfFreq = freq.QuadPart;
- }
- return perfFreq;
-}
-
-void Timer::initializeTimerSystem()
-{
- timeBeginPeriod(1);
- InitializeCriticalSection(&WinAPI_GetTimeCS);
-
-}
-void Timer::shutdownTimerSystem()
-{
- DeleteCriticalSection(&WinAPI_GetTimeCS);
- timeEndPeriod(1);
-}
-
-#else // !OVR_OS_WIN32
-
-
-//------------------------------------------------------------------------
-// *** Standard OS Timer
-
-UInt32 Timer::GetTicksMs()
-{
- return (UInt32)(GetProfileTicks() / 1000);
-}
-// The profile ticks implementation is just fine for a normal timer.
-UInt64 Timer::GetTicks()
-{
- return GetProfileTicks();
-}
-
-void Timer::initializeTimerSystem()
-{
-}
-void Timer::shutdownTimerSystem()
-{
-}
-
-UInt64 Timer::GetRawTicks()
-{
- // TODO: prefer rdtsc when available?
-
- // Return microseconds.
- struct timeval tv;
- UInt64 result;
-
- gettimeofday(&tv, 0);
-
- result = (UInt64)tv.tv_sec * 1000000;
- result += tv.tv_usec;
-
- return result;
-}
-
-UInt64 Timer::GetRawFrequency()
-{
- return MksPerSecond;
-}
-
-#endif // !OVR_OS_WIN32
-
-
-
-} // OVR
-
+/************************************************************************************
+
+Filename : OVR_Timer.cpp
+Content : Provides static functions for precise timing
+Created : September 19, 2012
+Notes :
+
+Copyright : Copyright 2012 Oculus VR, Inc. All Rights reserved.
+
+Use of this software is subject to the terms of the Oculus license
+agreement provided at the time of installation or download, or which
+otherwise accompanies this software in either electronic or hard copy form.
+
+************************************************************************************/
+
+#include "OVR_Timer.h"
+
+#if defined (OVR_OS_WIN32)
+#include <windows.h>
+
+#else
+#include <sys/time.h>
+#endif
+
+namespace OVR {
+
+//-----------------------------------------------------------------------------------
+// ***** Timer Class
+
+UInt64 Timer::GetProfileTicks()
+{
+ return (GetRawTicks() * MksPerSecond) / GetRawFrequency();
+}
+double Timer::GetProfileSeconds()
+{
+ static UInt64 StartTime = GetProfileTicks();
+ return TicksToSeconds(GetProfileTicks()-StartTime);
+}
+
+
+//------------------------------------------------------------------------
+// *** Win32 Specific Timer
+
+#if (defined (OVR_OS_WIN32))
+
+CRITICAL_SECTION WinAPI_GetTimeCS;
+volatile UInt32 WinAPI_OldTime = 0;
+volatile UInt32 WinAPI_WrapCounter = 0;
+
+
+UInt32 Timer::GetTicksMs()
+{
+ return timeGetTime();
+}
+
+UInt64 Timer::GetTicks()
+{
+ DWORD ticks = timeGetTime();
+ UInt64 result;
+
+ // On Win32 QueryPerformanceFrequency is unreliable due to SMP and
+ // performance levels, so use this logic to detect wrapping and track
+ // high bits.
+ ::EnterCriticalSection(&WinAPI_GetTimeCS);
+
+ if (WinAPI_OldTime > ticks)
+ WinAPI_WrapCounter++;
+ WinAPI_OldTime = ticks;
+
+ result = (UInt64(WinAPI_WrapCounter) << 32) | ticks;
+ ::LeaveCriticalSection(&WinAPI_GetTimeCS);
+
+ return result * MksPerMs;
+}
+
+UInt64 Timer::GetRawTicks()
+{
+ LARGE_INTEGER li;
+ QueryPerformanceCounter(&li);
+ return li.QuadPart;
+}
+
+UInt64 Timer::GetRawFrequency()
+{
+ static UInt64 perfFreq = 0;
+ if (perfFreq == 0)
+ {
+ LARGE_INTEGER freq;
+ QueryPerformanceFrequency(&freq);
+ perfFreq = freq.QuadPart;
+ }
+ return perfFreq;
+}
+
+void Timer::initializeTimerSystem()
+{
+ timeBeginPeriod(1);
+ InitializeCriticalSection(&WinAPI_GetTimeCS);
+
+}
+void Timer::shutdownTimerSystem()
+{
+ DeleteCriticalSection(&WinAPI_GetTimeCS);
+ timeEndPeriod(1);
+}
+
+#else // !OVR_OS_WIN32
+
+
+//------------------------------------------------------------------------
+// *** Standard OS Timer
+
+UInt32 Timer::GetTicksMs()
+{
+ return (UInt32)(GetProfileTicks() / 1000);
+}
+// The profile ticks implementation is just fine for a normal timer.
+UInt64 Timer::GetTicks()
+{
+ return GetProfileTicks();
+}
+
+void Timer::initializeTimerSystem()
+{
+}
+void Timer::shutdownTimerSystem()
+{
+}
+
+UInt64 Timer::GetRawTicks()
+{
+ // TODO: prefer rdtsc when available?
+
+ // Return microseconds.
+ struct timeval tv;
+ UInt64 result;
+
+ gettimeofday(&tv, 0);
+
+ result = (UInt64)tv.tv_sec * 1000000;
+ result += tv.tv_usec;
+
+ return result;
+}
+
+UInt64 Timer::GetRawFrequency()
+{
+ return MksPerSecond;
+}
+
+#endif // !OVR_OS_WIN32
+
+
+
+} // OVR
+
diff --git a/LibOVR/Src/Kernel/OVR_Timer.h b/LibOVR/Src/Kernel/OVR_Timer.h
index 0b71912..778dce8 100644
--- a/LibOVR/Src/Kernel/OVR_Timer.h
+++ b/LibOVR/Src/Kernel/OVR_Timer.h
@@ -1,100 +1,100 @@
-/************************************************************************************
-
-PublicHeader: OVR
-Filename : OVR_Timer.h
-Content : Provides static functions for precise timing
-Created : September 19, 2012
-Notes :
-
-Copyright : Copyright 2012 Oculus VR, Inc. All Rights reserved.
-
-Use of this software is subject to the terms of the Oculus license
-agreement provided at the time of installation or download, or which
-otherwise accompanies this software in either electronic or hard copy form.
-
-************************************************************************************/
-
-#ifndef OVR_Timer_h
-#define OVR_Timer_h
-
-#include "OVR_Types.h"
-
-namespace OVR {
-
-//-----------------------------------------------------------------------------------
-// ***** Timer
-
-// Timer class defines a family of static functions used for application
-// timing and profiling.
-
-class Timer
-{
-public:
- enum {
- MsPerSecond = 1000, // Milliseconds in one second.
- MksPerMs = 1000, // Microseconds in one millisecond.
- MksPerSecond = MsPerSecond * MksPerMs
- };
-
-
- // ***** Timing APIs for Application
- // These APIs should be used to guide animation and other program functions
- // that require precision.
-
- // Returns ticks in milliseconds, as a 32-bit number. May wrap around every
- // 49.2 days. Use either time difference of two values of GetTicks to avoid
- // wrap-around. GetTicksMs may perform better then GetTicks.
- static UInt32 OVR_STDCALL GetTicksMs();
-
- // GetTicks returns general-purpose high resolution application timer value,
- // measured in microseconds (mks, or 1/1000000 of a second). The actual precision
- // is system-specific and may be much lower, such as 1 ms.
- static UInt64 OVR_STDCALL GetTicks();
-
-
- // ***** Profiling APIs.
- // These functions should be used for profiling, but may have system specific
- // artifacts that make them less appropriate for general system use.
- // On Win32, for example these rely on QueryPerformanceConter may have
- // problems with thread-core switching and power modes.
-
- // Return a hi-res timer value in mks (1/1000000 of a sec).
- // Generally you want to call this at the start and end of an
- // operation, and pass the difference to
- // TicksToSeconds() to find out how long the operation took.
- static UInt64 OVR_STDCALL GetProfileTicks();
-
- // More convenient zero-based profile timer in seconds. First call initializes
- // the "zero" value; future calls return the difference. Not thread safe for first call.
- // Due to low precision of Double, may malfunction after long runtime.
- static double OVR_STDCALL GetProfileSeconds();
-
- // Get the raw cycle counter value, providing the maximum possible timer resolution.
- static UInt64 OVR_STDCALL GetRawTicks();
- static UInt64 OVR_STDCALL GetRawFrequency();
-
-
- // ***** Tick and time unit conversion.
-
- // Convert micro-second ticks value into seconds value.
- static inline double TicksToSeconds(UInt64 ticks)
- {
- return static_cast<double>(ticks) * (1.0 / (double)MksPerSecond);
- }
- // Convert Raw or frequency-unit ticks to seconds based on specified frequency.
- static inline double RawTicksToSeconds(UInt64 rawTicks, UInt64 rawFrequency)
- {
- return static_cast<double>(rawTicks) * rawFrequency;
- }
-
-private:
- friend class System;
- // System called during program startup/shutdown.
- static void initializeTimerSystem();
- static void shutdownTimerSystem();
-};
-
-
-} // Scaleform::Timer
-
-#endif
+/************************************************************************************
+
+PublicHeader: OVR
+Filename : OVR_Timer.h
+Content : Provides static functions for precise timing
+Created : September 19, 2012
+Notes :
+
+Copyright : Copyright 2012 Oculus VR, Inc. All Rights reserved.
+
+Use of this software is subject to the terms of the Oculus license
+agreement provided at the time of installation or download, or which
+otherwise accompanies this software in either electronic or hard copy form.
+
+************************************************************************************/
+
+#ifndef OVR_Timer_h
+#define OVR_Timer_h
+
+#include "OVR_Types.h"
+
+namespace OVR {
+
+//-----------------------------------------------------------------------------------
+// ***** Timer
+
+// Timer class defines a family of static functions used for application
+// timing and profiling.
+
+class Timer
+{
+public:
+ enum {
+ MsPerSecond = 1000, // Milliseconds in one second.
+ MksPerMs = 1000, // Microseconds in one millisecond.
+ MksPerSecond = MsPerSecond * MksPerMs
+ };
+
+
+ // ***** Timing APIs for Application
+ // These APIs should be used to guide animation and other program functions
+ // that require precision.
+
+ // Returns ticks in milliseconds, as a 32-bit number. May wrap around every
+ // 49.2 days. Use either time difference of two values of GetTicks to avoid
+ // wrap-around. GetTicksMs may perform better then GetTicks.
+ static UInt32 OVR_STDCALL GetTicksMs();
+
+ // GetTicks returns general-purpose high resolution application timer value,
+ // measured in microseconds (mks, or 1/1000000 of a second). The actual precision
+ // is system-specific and may be much lower, such as 1 ms.
+ static UInt64 OVR_STDCALL GetTicks();
+
+
+ // ***** Profiling APIs.
+ // These functions should be used for profiling, but may have system specific
+ // artifacts that make them less appropriate for general system use.
+ // On Win32, for example these rely on QueryPerformanceConter may have
+ // problems with thread-core switching and power modes.
+
+ // Return a hi-res timer value in mks (1/1000000 of a sec).
+ // Generally you want to call this at the start and end of an
+ // operation, and pass the difference to
+ // TicksToSeconds() to find out how long the operation took.
+ static UInt64 OVR_STDCALL GetProfileTicks();
+
+ // More convenient zero-based profile timer in seconds. First call initializes
+ // the "zero" value; future calls return the difference. Not thread safe for first call.
+ // Due to low precision of Double, may malfunction after long runtime.
+ static double OVR_STDCALL GetProfileSeconds();
+
+ // Get the raw cycle counter value, providing the maximum possible timer resolution.
+ static UInt64 OVR_STDCALL GetRawTicks();
+ static UInt64 OVR_STDCALL GetRawFrequency();
+
+
+ // ***** Tick and time unit conversion.
+
+ // Convert micro-second ticks value into seconds value.
+ static inline double TicksToSeconds(UInt64 ticks)
+ {
+ return static_cast<double>(ticks) * (1.0 / (double)MksPerSecond);
+ }
+ // Convert Raw or frequency-unit ticks to seconds based on specified frequency.
+ static inline double RawTicksToSeconds(UInt64 rawTicks, UInt64 rawFrequency)
+ {
+ return static_cast<double>(rawTicks) * rawFrequency;
+ }
+
+private:
+ friend class System;
+ // System called during program startup/shutdown.
+ static void initializeTimerSystem();
+ static void shutdownTimerSystem();
+};
+
+
+} // Scaleform::Timer
+
+#endif
diff --git a/LibOVR/Src/Kernel/OVR_Types.h b/LibOVR/Src/Kernel/OVR_Types.h
index 40eb156..75493aa 100644
--- a/LibOVR/Src/Kernel/OVR_Types.h
+++ b/LibOVR/Src/Kernel/OVR_Types.h
@@ -1,456 +1,456 @@
-/************************************************************************************
-
-PublicHeader: OVR.h
-Filename : OVR_Types.h
-Content : Standard library defines and simple types
-Created : September 19, 2012
-Notes :
-
-Copyright : Copyright 2012 Oculus VR, Inc. All Rights reserved.
-
-Use of this software is subject to the terms of the Oculus license
-agreement provided at the time of installation or download, or which
-otherwise accompanies this software in either electronic or hard copy form.
-
-************************************************************************************/
-
-#ifndef OVR_Types_H
-#define OVR_Types_H
-
-//-----------------------------------------------------------------------------------
-// ****** Operating System
-//
-// Type definitions exist for the following operating systems: (OVR_OS_x)
-//
-// WIN32 - Win32 (Windows 95/98/ME and Windows NT/2000/XP)
-// DARWIN - Darwin OS (Mac OS X)
-// LINUX - Linux
-// ANDROID - Android
-// IPHONE - iPhone
-
-#if (defined(__APPLE__) && (defined(__GNUC__) ||\
- defined(__xlC__) || defined(__xlc__))) || defined(__MACOS__)
-# if (defined(__ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__) || defined(__IPHONE_OS_VERSION_MIN_REQUIRED))
-# define OVR_OS_IPHONE
-# else
-# define OVR_OS_DARWIN
-# define OVR_OS_MAC
-# endif
-#elif (defined(WIN64) || defined(_WIN64) || defined(__WIN64__))
-# define OVR_OS_WIN32
-#elif (defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(__NT__))
-# define OVR_OS_WIN32
-#elif defined(__linux__) || defined(__linux)
-# define OVR_OS_LINUX
-#else
-# define OVR_OS_OTHER
-#endif
-
-#if defined(ANDROID)
-# define OVR_OS_ANDROID
-#endif
-
-
-//-----------------------------------------------------------------------------------
-// ***** CPU Architecture
-//
-// The following CPUs are defined: (OVR_CPU_x)
-//
-// X86 - x86 (IA-32)
-// X86_64 - x86_64 (amd64)
-// PPC - PowerPC
-// PPC64 - PowerPC64
-// MIPS - MIPS
-// OTHER - CPU for which no special support is present or needed
-
-
-#if defined(__x86_64__) || defined(WIN64) || defined(_WIN64) || defined(__WIN64__)
-# define OVR_CPU_X86_64
-# define OVR_64BIT_POINTERS
-#elif defined(__i386__) || defined(OVR_OS_WIN32)
-# define OVR_CPU_X86
-#elif defined(__powerpc64__)
-# define OVR_CPU_PPC64
-#elif defined(__ppc__)
-# define OVR_CPU_PPC
-#elif defined(__mips__) || defined(__MIPSEL__)
-# define OVR_CPU_MIPS
-#elif defined(__arm__)
-# define OVR_CPU_ARM
-#else
-# define OVR_CPU_OTHER
-#endif
-
-//-----------------------------------------------------------------------------------
-// ***** Co-Processor Architecture
-//
-// The following co-processors are defined: (OVR_CPU_x)
-//
-// SSE - Available on all modern x86 processors.
-// Altivec - Available on all modern ppc processors.
-// Neon - Available on some armv7+ processors.
-
-#if defined(__SSE__) || defined(OVR_OS_WIN32)
-# define OVR_CPU_SSE
-#endif // __SSE__
-
-#if defined( __ALTIVEC__ )
-# define OVR_CPU_ALTIVEC
-#endif // __ALTIVEC__
-
-#if defined(__ARM_NEON__)
-# define OVR_CPU_ARM_NEON
-#endif // __ARM_NEON__
-
-
-//-----------------------------------------------------------------------------------
-// ***** Compiler
-//
-// The following compilers are defined: (OVR_CC_x)
-//
-// MSVC - Microsoft Visual C/C++
-// INTEL - Intel C++ for Linux / Windows
-// GNU - GNU C++
-// ARM - ARM C/C++
-
-#if defined(__INTEL_COMPILER)
-// Intel 4.0 = 400
-// Intel 5.0 = 500
-// Intel 6.0 = 600
-// Intel 8.0 = 800
-// Intel 9.0 = 900
-# define OVR_CC_INTEL __INTEL_COMPILER
-
-#elif defined(_MSC_VER)
-// MSVC 5.0 = 1100
-// MSVC 6.0 = 1200
-// MSVC 7.0 (VC2002) = 1300
-// MSVC 7.1 (VC2003) = 1310
-// MSVC 8.0 (VC2005) = 1400
-// MSVC 9.0 (VC2008) = 1500
-// MSVC 10.0 (VC2010) = 1600
-# define OVR_CC_MSVC _MSC_VER
-
-#elif defined(__GNUC__)
-# define OVR_CC_GNU
-
-#elif defined(__CC_ARM)
-# define OVR_CC_ARM
-
-#else
-# error "Oculus does not support this Compiler"
-#endif
-
-
-//-----------------------------------------------------------------------------------
-// ***** Compiler Warnings
-
-// Disable MSVC warnings
-#if defined(OVR_CC_MSVC)
-# pragma warning(disable : 4127) // Inconsistent dll linkage
-# pragma warning(disable : 4530) // Exception handling
-# if (OVR_CC_MSVC<1300)
-# pragma warning(disable : 4514) // Unreferenced inline function has been removed
-# pragma warning(disable : 4710) // Function not inlined
-# pragma warning(disable : 4714) // _force_inline not inlined
-# pragma warning(disable : 4786) // Debug variable name longer than 255 chars
-# endif // (OVR_CC_MSVC<1300)
-#endif // (OVR_CC_MSVC)
-
-
-
-// *** Linux Unicode - must come before Standard Includes
-
-#ifdef OVR_OS_LINUX
-// Use glibc unicode functions on linux.
-# ifndef _GNU_SOURCE
-# define _GNU_SOURCE
-# endif
-#endif
-
-//-----------------------------------------------------------------------------------
-// ***** Standard Includes
-//
-#include <stddef.h>
-#include <limits.h>
-#include <float.h>
-
-
-// MSVC Based Memory Leak checking - for now
-#if defined(OVR_CC_MSVC) && defined(OVR_BUILD_DEBUG)
-# define _CRTDBG_MAP_ALLOC
-# include <stdlib.h>
-# include <crtdbg.h>
-
-// Uncomment this to help debug memory leaks under Visual Studio in OVR apps only.
-// This shouldn't be defined in customer releases.
-# ifndef OVR_DEFINE_NEW
-# define OVR_DEFINE_NEW new(__FILE__, __LINE__)
-# define new OVR_DEFINE_NEW
-# endif
-
-#endif
-
-
-//-----------------------------------------------------------------------------------
-// ***** Type definitions for Common Systems
-
-namespace OVR {
-
-typedef char Char;
-
-// Pointer-sized integer
-typedef size_t UPInt;
-typedef ptrdiff_t SPInt;
-
-
-#if defined(OVR_OS_WIN32)
-
-typedef char SByte; // 8 bit Integer (Byte)
-typedef unsigned char UByte;
-typedef short SInt16; // 16 bit Integer (Word)
-typedef unsigned short UInt16;
-typedef long SInt32; // 32 bit Integer
-typedef unsigned long UInt32;
-typedef __int64 SInt64; // 64 bit Integer (QWord)
-typedef unsigned __int64 UInt64;
-
-
-#elif defined(OVR_OS_MAC) || defined(OVR_OS_IPHONE) || defined(OVR_CC_GNU)
-
-typedef int SByte __attribute__((__mode__ (__QI__)));
-typedef unsigned int UByte __attribute__((__mode__ (__QI__)));
-typedef int SInt16 __attribute__((__mode__ (__HI__)));
-typedef unsigned int UInt16 __attribute__((__mode__ (__HI__)));
-typedef int SInt32 __attribute__((__mode__ (__SI__)));
-typedef unsigned int UInt32 __attribute__((__mode__ (__SI__)));
-typedef int SInt64 __attribute__((__mode__ (__DI__)));
-typedef unsigned int UInt64 __attribute__((__mode__ (__DI__)));
-
-#else
-
-#include <sys/types.h>
-typedef int8_t SByte;
-typedef uint8_t UByte;
-typedef int16_t SInt16;
-typedef uint16_t UInt16;
-typedef int32_t SInt32;
-typedef uint32_t UInt32;
-typedef int64_t SInt64;
-typedef uint64_t UInt64;
-
-#endif
-
-
-// ***** BaseTypes Namespace
-
-// BaseTypes namespace is explicitly declared to allow base types to be used
-// by customers directly without other contents of OVR namespace.
-//
-// Its is expected that GFx samples will declare 'using namespace OVR::BaseTypes'
-// to allow using these directly without polluting the target scope with other
-// OVR declarations, such as Ptr<>, String or Mutex.
-namespace BaseTypes
-{
- using OVR::UPInt;
- using OVR::SPInt;
- using OVR::UByte;
- using OVR::SByte;
- using OVR::UInt16;
- using OVR::SInt16;
- using OVR::UInt32;
- using OVR::SInt32;
- using OVR::UInt64;
- using OVR::SInt64;
-} // OVR::BaseTypes
-
-} // OVR
-
-
-//-----------------------------------------------------------------------------------
-// ***** Macro Definitions
-//
-// We define the following:
-//
-// OVR_BYTE_ORDER - Defined to either OVR_LITTLE_ENDIAN or OVR_BIG_ENDIAN
-// OVR_FORCE_INLINE - Forces inline expansion of function
-// OVR_ASM - Assembly language prefix
-// OVR_STR - Prefixes string with L"" if building unicode
-//
-// OVR_STDCALL - Use stdcall calling convention (Pascal arg order)
-// OVR_CDECL - Use cdecl calling convention (C argument order)
-// OVR_FASTCALL - Use fastcall calling convention (registers)
-//
-
-// Byte order constants, OVR_BYTE_ORDER is defined to be one of these.
-#define OVR_LITTLE_ENDIAN 1
-#define OVR_BIG_ENDIAN 2
-
-
-// Force inline substitute - goes before function declaration
-#if defined(OVR_CC_MSVC)
-# define OVR_FORCE_INLINE __forceinline
-#elif defined(OVR_CC_GNU)
-# define OVR_FORCE_INLINE __attribute__((always_inline))
-#else
-# define OVR_FORCE_INLINE inline
-#endif // OVR_CC_MSVC
-
-
-#if defined(OVR_OS_WIN32)
-
- // ***** Win32
-
- // Byte order
- #define OVR_BYTE_ORDER OVR_LITTLE_ENDIAN
-
- // Calling convention - goes after function return type but before function name
- #ifdef __cplusplus_cli
- # define OVR_FASTCALL __stdcall
- #else
- # define OVR_FASTCALL __fastcall
- #endif
-
- #define OVR_STDCALL __stdcall
- #define OVR_CDECL __cdecl
-
-
- // Assembly macros
- #if defined(OVR_CC_MSVC)
- # define OVR_ASM _asm
- #else
- # define OVR_ASM asm
- #endif // (OVR_CC_MSVC)
-
- #ifdef UNICODE
- # define OVR_STR(str) L##str
- #else
- # define OVR_STR(str) str
- #endif // UNICODE
-
-#else
-
- // **** Standard systems
-
- #if (defined(BYTE_ORDER) && (BYTE_ORDER == BIG_ENDIAN))|| \
- (defined(_BYTE_ORDER) && (_BYTE_ORDER == _BIG_ENDIAN))
- # define OVR_BYTE_ORDER OVR_BIG_ENDIAN
- #elif (defined(__ARMEB__) || defined(OVR_CPU_PPC) || defined(OVR_CPU_PPC64))
- # define OVR_BYTE_ORDER OVR_BIG_ENDIAN
- #else
- # define OVR_BYTE_ORDER OVR_LITTLE_ENDIAN
- #endif
-
- // Assembly macros
- #define OVR_ASM __asm__
- #define OVR_ASM_PROC(procname) OVR_ASM
- #define OVR_ASM_END OVR_ASM
-
- // Calling convention - goes after function return type but before function name
- #define OVR_FASTCALL
- #define OVR_STDCALL
- #define OVR_CDECL
-
-#endif // defined(OVR_OS_WIN32)
-
-
-
-//-----------------------------------------------------------------------------------
-// ***** OVR_DEBUG_BREAK, OVR_ASSERT
-//
-// If not in debug build, macros do nothing
-#ifndef OVR_BUILD_DEBUG
-
-# define OVR_DEBUG_BREAK ((void)0)
-# define OVR_ASSERT(p) ((void)0)
-
-#else
-
-// Microsoft Win32 specific debugging support
-#if defined(OVR_OS_WIN32)
-# ifdef OVR_CPU_X86
-# if defined(__cplusplus_cli)
-# define OVR_DEBUG_BREAK do { __debugbreak(); } while(0)
-# elif defined(OVR_CC_GNU)
-# define OVR_DEBUG_BREAK do { OVR_ASM("int $3\n\t"); } while(0)
-# else
-# define OVR_DEBUG_BREAK do { OVR_ASM int 3 } while (0)
-# endif
-# else
-# define OVR_DEBUG_BREAK do { __debugbreak(); } while(0)
-# endif
-// Unix specific debugging support
-#elif defined(OVR_CPU_X86) || defined(OVR_CPU_X86_64)
-# define OVR_DEBUG_BREAK do { OVR_ASM("int $3\n\t"); } while(0)
-#else
-# define OVR_DEBUG_BREAK do { *((int *) 0) = 1; } while(0)
-#endif
-
-// This will cause compiler breakpoint
-#define OVR_ASSERT(p) do { if (!(p)) { OVR_DEBUG_BREAK; } } while(0)
-
-#endif // OVR_BUILD_DEBUG
-
-
-// Compile-time assert; produces compiler error if condition is false
-#define OVR_COMPILER_ASSERT(x) { int zero = 0; switch(zero) {case 0: case x:;} }
-
-
-
-//-----------------------------------------------------------------------------------
-// ***** OVR_UNUSED - Unused Argument handling
-
-// Macro to quiet compiler warnings about unused parameters/variables.
-#if defined(OVR_CC_GNU)
-# define OVR_UNUSED(a) do {__typeof__ (&a) __attribute__ ((unused)) __tmp = &a; } while(0)
-#else
-# define OVR_UNUSED(a) (a)
-#endif
-
-#define OVR_UNUSED1(a1) OVR_UNUSED(a1)
-#define OVR_UNUSED2(a1,a2) OVR_UNUSED(a1); OVR_UNUSED(a2)
-#define OVR_UNUSED3(a1,a2,a3) OVR_UNUSED2(a1,a2); OVR_UNUSED(a3)
-#define OVR_UNUSED4(a1,a2,a3,a4) OVR_UNUSED3(a1,a2,a3); OVR_UNUSED(a4)
-#define OVR_UNUSED5(a1,a2,a3,a4,a5) OVR_UNUSED4(a1,a2,a3,a4); OVR_UNUSED(a5)
-#define OVR_UNUSED6(a1,a2,a3,a4,a5,a6) OVR_UNUSED4(a1,a2,a3,a4); OVR_UNUSED2(a5,a6)
-#define OVR_UNUSED7(a1,a2,a3,a4,a5,a6,a7) OVR_UNUSED4(a1,a2,a3,a4); OVR_UNUSED3(a5,a6,a7)
-#define OVR_UNUSED8(a1,a2,a3,a4,a5,a6,a7,a8) OVR_UNUSED4(a1,a2,a3,a4); OVR_UNUSED4(a5,a6,a7,a8)
-#define OVR_UNUSED9(a1,a2,a3,a4,a5,a6,a7,a8,a9) OVR_UNUSED4(a1,a2,a3,a4); OVR_UNUSED5(a5,a6,a7,a8,a9)
-
-
-//-----------------------------------------------------------------------------------
-// ***** Configuration Macros
-
-// SF Build type
-#ifdef OVR_BUILD_DEBUG
-# define OVR_BUILD_STRING "Debug"
-#else
-# define OVR_BUILD_STRING "Release"
-#endif
-
-
-//// Enables SF Debugging information
-//# define OVR_BUILD_DEBUG
-
-// OVR_DEBUG_STATEMENT injects a statement only in debug builds.
-// OVR_DEBUG_SELECT injects first argument in debug builds, second argument otherwise.
-#ifdef OVR_BUILD_DEBUG
-#define OVR_DEBUG_STATEMENT(s) s
-#define OVR_DEBUG_SELECT(d, nd) d
-#else
-#define OVR_DEBUG_STATEMENT(s)
-#define OVR_DEBUG_SELECT(d, nd) nd
-#endif
-
-
-#define OVR_ENABLE_THREADS
-//
-// Prevents OVR from defining new within
-// type macros, so developers can override
-// new using the #define new new(...) trick
-// - used with OVR_DEFINE_NEW macro
-//# define OVR_BUILD_DEFINE_NEW
-//
-
-
-#endif // OVR_Types_h
+/************************************************************************************
+
+PublicHeader: OVR.h
+Filename : OVR_Types.h
+Content : Standard library defines and simple types
+Created : September 19, 2012
+Notes :
+
+Copyright : Copyright 2012 Oculus VR, Inc. All Rights reserved.
+
+Use of this software is subject to the terms of the Oculus license
+agreement provided at the time of installation or download, or which
+otherwise accompanies this software in either electronic or hard copy form.
+
+************************************************************************************/
+
+#ifndef OVR_Types_H
+#define OVR_Types_H
+
+//-----------------------------------------------------------------------------------
+// ****** Operating System
+//
+// Type definitions exist for the following operating systems: (OVR_OS_x)
+//
+// WIN32 - Win32 (Windows 95/98/ME and Windows NT/2000/XP)
+// DARWIN - Darwin OS (Mac OS X)
+// LINUX - Linux
+// ANDROID - Android
+// IPHONE - iPhone
+
+#if (defined(__APPLE__) && (defined(__GNUC__) ||\
+ defined(__xlC__) || defined(__xlc__))) || defined(__MACOS__)
+# if (defined(__ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__) || defined(__IPHONE_OS_VERSION_MIN_REQUIRED))
+# define OVR_OS_IPHONE
+# else
+# define OVR_OS_DARWIN
+# define OVR_OS_MAC
+# endif
+#elif (defined(WIN64) || defined(_WIN64) || defined(__WIN64__))
+# define OVR_OS_WIN32
+#elif (defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(__NT__))
+# define OVR_OS_WIN32
+#elif defined(__linux__) || defined(__linux)
+# define OVR_OS_LINUX
+#else
+# define OVR_OS_OTHER
+#endif
+
+#if defined(ANDROID)
+# define OVR_OS_ANDROID
+#endif
+
+
+//-----------------------------------------------------------------------------------
+// ***** CPU Architecture
+//
+// The following CPUs are defined: (OVR_CPU_x)
+//
+// X86 - x86 (IA-32)
+// X86_64 - x86_64 (amd64)
+// PPC - PowerPC
+// PPC64 - PowerPC64
+// MIPS - MIPS
+// OTHER - CPU for which no special support is present or needed
+
+
+#if defined(__x86_64__) || defined(WIN64) || defined(_WIN64) || defined(__WIN64__)
+# define OVR_CPU_X86_64
+# define OVR_64BIT_POINTERS
+#elif defined(__i386__) || defined(OVR_OS_WIN32)
+# define OVR_CPU_X86
+#elif defined(__powerpc64__)
+# define OVR_CPU_PPC64
+#elif defined(__ppc__)
+# define OVR_CPU_PPC
+#elif defined(__mips__) || defined(__MIPSEL__)
+# define OVR_CPU_MIPS
+#elif defined(__arm__)
+# define OVR_CPU_ARM
+#else
+# define OVR_CPU_OTHER
+#endif
+
+//-----------------------------------------------------------------------------------
+// ***** Co-Processor Architecture
+//
+// The following co-processors are defined: (OVR_CPU_x)
+//
+// SSE - Available on all modern x86 processors.
+// Altivec - Available on all modern ppc processors.
+// Neon - Available on some armv7+ processors.
+
+#if defined(__SSE__) || defined(OVR_OS_WIN32)
+# define OVR_CPU_SSE
+#endif // __SSE__
+
+#if defined( __ALTIVEC__ )
+# define OVR_CPU_ALTIVEC
+#endif // __ALTIVEC__
+
+#if defined(__ARM_NEON__)
+# define OVR_CPU_ARM_NEON
+#endif // __ARM_NEON__
+
+
+//-----------------------------------------------------------------------------------
+// ***** Compiler
+//
+// The following compilers are defined: (OVR_CC_x)
+//
+// MSVC - Microsoft Visual C/C++
+// INTEL - Intel C++ for Linux / Windows
+// GNU - GNU C++
+// ARM - ARM C/C++
+
+#if defined(__INTEL_COMPILER)
+// Intel 4.0 = 400
+// Intel 5.0 = 500
+// Intel 6.0 = 600
+// Intel 8.0 = 800
+// Intel 9.0 = 900
+# define OVR_CC_INTEL __INTEL_COMPILER
+
+#elif defined(_MSC_VER)
+// MSVC 5.0 = 1100
+// MSVC 6.0 = 1200
+// MSVC 7.0 (VC2002) = 1300
+// MSVC 7.1 (VC2003) = 1310
+// MSVC 8.0 (VC2005) = 1400
+// MSVC 9.0 (VC2008) = 1500
+// MSVC 10.0 (VC2010) = 1600
+# define OVR_CC_MSVC _MSC_VER
+
+#elif defined(__GNUC__)
+# define OVR_CC_GNU
+
+#elif defined(__CC_ARM)
+# define OVR_CC_ARM
+
+#else
+# error "Oculus does not support this Compiler"
+#endif
+
+
+//-----------------------------------------------------------------------------------
+// ***** Compiler Warnings
+
+// Disable MSVC warnings
+#if defined(OVR_CC_MSVC)
+# pragma warning(disable : 4127) // Inconsistent dll linkage
+# pragma warning(disable : 4530) // Exception handling
+# if (OVR_CC_MSVC<1300)
+# pragma warning(disable : 4514) // Unreferenced inline function has been removed
+# pragma warning(disable : 4710) // Function not inlined
+# pragma warning(disable : 4714) // _force_inline not inlined
+# pragma warning(disable : 4786) // Debug variable name longer than 255 chars
+# endif // (OVR_CC_MSVC<1300)
+#endif // (OVR_CC_MSVC)
+
+
+
+// *** Linux Unicode - must come before Standard Includes
+
+#ifdef OVR_OS_LINUX
+// Use glibc unicode functions on linux.
+# ifndef _GNU_SOURCE
+# define _GNU_SOURCE
+# endif
+#endif
+
+//-----------------------------------------------------------------------------------
+// ***** Standard Includes
+//
+#include <stddef.h>
+#include <limits.h>
+#include <float.h>
+
+
+// MSVC Based Memory Leak checking - for now
+#if defined(OVR_CC_MSVC) && defined(OVR_BUILD_DEBUG)
+# define _CRTDBG_MAP_ALLOC
+# include <stdlib.h>
+# include <crtdbg.h>
+
+// Uncomment this to help debug memory leaks under Visual Studio in OVR apps only.
+// This shouldn't be defined in customer releases.
+# ifndef OVR_DEFINE_NEW
+# define OVR_DEFINE_NEW new(__FILE__, __LINE__)
+# define new OVR_DEFINE_NEW
+# endif
+
+#endif
+
+
+//-----------------------------------------------------------------------------------
+// ***** Type definitions for Common Systems
+
+namespace OVR {
+
+typedef char Char;
+
+// Pointer-sized integer
+typedef size_t UPInt;
+typedef ptrdiff_t SPInt;
+
+
+#if defined(OVR_OS_WIN32)
+
+typedef char SByte; // 8 bit Integer (Byte)
+typedef unsigned char UByte;
+typedef short SInt16; // 16 bit Integer (Word)
+typedef unsigned short UInt16;
+typedef long SInt32; // 32 bit Integer
+typedef unsigned long UInt32;
+typedef __int64 SInt64; // 64 bit Integer (QWord)
+typedef unsigned __int64 UInt64;
+
+
+#elif defined(OVR_OS_MAC) || defined(OVR_OS_IPHONE) || defined(OVR_CC_GNU)
+
+typedef int SByte __attribute__((__mode__ (__QI__)));
+typedef unsigned int UByte __attribute__((__mode__ (__QI__)));
+typedef int SInt16 __attribute__((__mode__ (__HI__)));
+typedef unsigned int UInt16 __attribute__((__mode__ (__HI__)));
+typedef int SInt32 __attribute__((__mode__ (__SI__)));
+typedef unsigned int UInt32 __attribute__((__mode__ (__SI__)));
+typedef int SInt64 __attribute__((__mode__ (__DI__)));
+typedef unsigned int UInt64 __attribute__((__mode__ (__DI__)));
+
+#else
+
+#include <sys/types.h>
+typedef int8_t SByte;
+typedef uint8_t UByte;
+typedef int16_t SInt16;
+typedef uint16_t UInt16;
+typedef int32_t SInt32;
+typedef uint32_t UInt32;
+typedef int64_t SInt64;
+typedef uint64_t UInt64;
+
+#endif
+
+
+// ***** BaseTypes Namespace
+
+// BaseTypes namespace is explicitly declared to allow base types to be used
+// by customers directly without other contents of OVR namespace.
+//
+// Its is expected that GFx samples will declare 'using namespace OVR::BaseTypes'
+// to allow using these directly without polluting the target scope with other
+// OVR declarations, such as Ptr<>, String or Mutex.
+namespace BaseTypes
+{
+ using OVR::UPInt;
+ using OVR::SPInt;
+ using OVR::UByte;
+ using OVR::SByte;
+ using OVR::UInt16;
+ using OVR::SInt16;
+ using OVR::UInt32;
+ using OVR::SInt32;
+ using OVR::UInt64;
+ using OVR::SInt64;
+} // OVR::BaseTypes
+
+} // OVR
+
+
+//-----------------------------------------------------------------------------------
+// ***** Macro Definitions
+//
+// We define the following:
+//
+// OVR_BYTE_ORDER - Defined to either OVR_LITTLE_ENDIAN or OVR_BIG_ENDIAN
+// OVR_FORCE_INLINE - Forces inline expansion of function
+// OVR_ASM - Assembly language prefix
+// OVR_STR - Prefixes string with L"" if building unicode
+//
+// OVR_STDCALL - Use stdcall calling convention (Pascal arg order)
+// OVR_CDECL - Use cdecl calling convention (C argument order)
+// OVR_FASTCALL - Use fastcall calling convention (registers)
+//
+
+// Byte order constants, OVR_BYTE_ORDER is defined to be one of these.
+#define OVR_LITTLE_ENDIAN 1
+#define OVR_BIG_ENDIAN 2
+
+
+// Force inline substitute - goes before function declaration
+#if defined(OVR_CC_MSVC)
+# define OVR_FORCE_INLINE __forceinline
+#elif defined(OVR_CC_GNU)
+# define OVR_FORCE_INLINE __attribute__((always_inline))
+#else
+# define OVR_FORCE_INLINE inline
+#endif // OVR_CC_MSVC
+
+
+#if defined(OVR_OS_WIN32)
+
+ // ***** Win32
+
+ // Byte order
+ #define OVR_BYTE_ORDER OVR_LITTLE_ENDIAN
+
+ // Calling convention - goes after function return type but before function name
+ #ifdef __cplusplus_cli
+ # define OVR_FASTCALL __stdcall
+ #else
+ # define OVR_FASTCALL __fastcall
+ #endif
+
+ #define OVR_STDCALL __stdcall
+ #define OVR_CDECL __cdecl
+
+
+ // Assembly macros
+ #if defined(OVR_CC_MSVC)
+ # define OVR_ASM _asm
+ #else
+ # define OVR_ASM asm
+ #endif // (OVR_CC_MSVC)
+
+ #ifdef UNICODE
+ # define OVR_STR(str) L##str
+ #else
+ # define OVR_STR(str) str
+ #endif // UNICODE
+
+#else
+
+ // **** Standard systems
+
+ #if (defined(BYTE_ORDER) && (BYTE_ORDER == BIG_ENDIAN))|| \
+ (defined(_BYTE_ORDER) && (_BYTE_ORDER == _BIG_ENDIAN))
+ # define OVR_BYTE_ORDER OVR_BIG_ENDIAN
+ #elif (defined(__ARMEB__) || defined(OVR_CPU_PPC) || defined(OVR_CPU_PPC64))
+ # define OVR_BYTE_ORDER OVR_BIG_ENDIAN
+ #else
+ # define OVR_BYTE_ORDER OVR_LITTLE_ENDIAN
+ #endif
+
+ // Assembly macros
+ #define OVR_ASM __asm__
+ #define OVR_ASM_PROC(procname) OVR_ASM
+ #define OVR_ASM_END OVR_ASM
+
+ // Calling convention - goes after function return type but before function name
+ #define OVR_FASTCALL
+ #define OVR_STDCALL
+ #define OVR_CDECL
+
+#endif // defined(OVR_OS_WIN32)
+
+
+
+//-----------------------------------------------------------------------------------
+// ***** OVR_DEBUG_BREAK, OVR_ASSERT
+//
+// If not in debug build, macros do nothing
+#ifndef OVR_BUILD_DEBUG
+
+# define OVR_DEBUG_BREAK ((void)0)
+# define OVR_ASSERT(p) ((void)0)
+
+#else
+
+// Microsoft Win32 specific debugging support
+#if defined(OVR_OS_WIN32)
+# ifdef OVR_CPU_X86
+# if defined(__cplusplus_cli)
+# define OVR_DEBUG_BREAK do { __debugbreak(); } while(0)
+# elif defined(OVR_CC_GNU)
+# define OVR_DEBUG_BREAK do { OVR_ASM("int $3\n\t"); } while(0)
+# else
+# define OVR_DEBUG_BREAK do { OVR_ASM int 3 } while (0)
+# endif
+# else
+# define OVR_DEBUG_BREAK do { __debugbreak(); } while(0)
+# endif
+// Unix specific debugging support
+#elif defined(OVR_CPU_X86) || defined(OVR_CPU_X86_64)
+# define OVR_DEBUG_BREAK do { OVR_ASM("int $3\n\t"); } while(0)
+#else
+# define OVR_DEBUG_BREAK do { *((int *) 0) = 1; } while(0)
+#endif
+
+// This will cause compiler breakpoint
+#define OVR_ASSERT(p) do { if (!(p)) { OVR_DEBUG_BREAK; } } while(0)
+
+#endif // OVR_BUILD_DEBUG
+
+
+// Compile-time assert; produces compiler error if condition is false
+#define OVR_COMPILER_ASSERT(x) { int zero = 0; switch(zero) {case 0: case x:;} }
+
+
+
+//-----------------------------------------------------------------------------------
+// ***** OVR_UNUSED - Unused Argument handling
+
+// Macro to quiet compiler warnings about unused parameters/variables.
+#if defined(OVR_CC_GNU)
+# define OVR_UNUSED(a) do {__typeof__ (&a) __attribute__ ((unused)) __tmp = &a; } while(0)
+#else
+# define OVR_UNUSED(a) (a)
+#endif
+
+#define OVR_UNUSED1(a1) OVR_UNUSED(a1)
+#define OVR_UNUSED2(a1,a2) OVR_UNUSED(a1); OVR_UNUSED(a2)
+#define OVR_UNUSED3(a1,a2,a3) OVR_UNUSED2(a1,a2); OVR_UNUSED(a3)
+#define OVR_UNUSED4(a1,a2,a3,a4) OVR_UNUSED3(a1,a2,a3); OVR_UNUSED(a4)
+#define OVR_UNUSED5(a1,a2,a3,a4,a5) OVR_UNUSED4(a1,a2,a3,a4); OVR_UNUSED(a5)
+#define OVR_UNUSED6(a1,a2,a3,a4,a5,a6) OVR_UNUSED4(a1,a2,a3,a4); OVR_UNUSED2(a5,a6)
+#define OVR_UNUSED7(a1,a2,a3,a4,a5,a6,a7) OVR_UNUSED4(a1,a2,a3,a4); OVR_UNUSED3(a5,a6,a7)
+#define OVR_UNUSED8(a1,a2,a3,a4,a5,a6,a7,a8) OVR_UNUSED4(a1,a2,a3,a4); OVR_UNUSED4(a5,a6,a7,a8)
+#define OVR_UNUSED9(a1,a2,a3,a4,a5,a6,a7,a8,a9) OVR_UNUSED4(a1,a2,a3,a4); OVR_UNUSED5(a5,a6,a7,a8,a9)
+
+
+//-----------------------------------------------------------------------------------
+// ***** Configuration Macros
+
+// SF Build type
+#ifdef OVR_BUILD_DEBUG
+# define OVR_BUILD_STRING "Debug"
+#else
+# define OVR_BUILD_STRING "Release"
+#endif
+
+
+//// Enables SF Debugging information
+//# define OVR_BUILD_DEBUG
+
+// OVR_DEBUG_STATEMENT injects a statement only in debug builds.
+// OVR_DEBUG_SELECT injects first argument in debug builds, second argument otherwise.
+#ifdef OVR_BUILD_DEBUG
+#define OVR_DEBUG_STATEMENT(s) s
+#define OVR_DEBUG_SELECT(d, nd) d
+#else
+#define OVR_DEBUG_STATEMENT(s)
+#define OVR_DEBUG_SELECT(d, nd) nd
+#endif
+
+
+#define OVR_ENABLE_THREADS
+//
+// Prevents OVR from defining new within
+// type macros, so developers can override
+// new using the #define new new(...) trick
+// - used with OVR_DEFINE_NEW macro
+//# define OVR_BUILD_DEFINE_NEW
+//
+
+
+#endif // OVR_Types_h
diff --git a/LibOVR/Src/Kernel/OVR_UTF8Util.cpp b/LibOVR/Src/Kernel/OVR_UTF8Util.cpp
index 21485df..dd8350f 100644
--- a/LibOVR/Src/Kernel/OVR_UTF8Util.cpp
+++ b/LibOVR/Src/Kernel/OVR_UTF8Util.cpp
@@ -1,545 +1,545 @@
-/**************************************************************************
-
-Filename : OVR_UTF8Util.cpp
-Content : UTF8 Unicode character encoding/decoding support
-Created : September 19, 2012
-Notes :
-Notes : Much useful info at "UTF-8 and Unicode FAQ"
- http://www.cl.cam.ac.uk/~mgk25/unicode.html
-
-Copyright : Copyright 2012 Oculus VR, Inc. All Rights reserved.
-
-Use of this software is subject to the terms of the Oculus license
-agreement provided at the time of installation or download, or which
-otherwise accompanies this software in either electronic or hard copy form.
-
-************************************************************************************/
-
-#include "OVR_UTF8Util.h"
-
-namespace OVR { namespace UTF8Util {
-
-SPInt OVR_STDCALL GetLength(const char* buf, SPInt buflen)
-{
- const char* p = buf;
- SPInt length = 0;
-
- if (buflen != -1)
- {
- while (p - buf < buflen)
- {
- // We should be able to have ASStrings with 0 in the middle.
- UTF8Util::DecodeNextChar_Advance0(&p);
- length++;
- }
- }
- else
- {
- while (UTF8Util::DecodeNextChar_Advance0(&p))
- length++;
- }
-
- return length;
-}
-
-UInt32 OVR_STDCALL GetCharAt(SPInt index, const char* putf8str, SPInt length)
-{
- const char* buf = putf8str;
- UInt32 c = 0;
-
- if (length != -1)
- {
- while (buf - putf8str < length)
- {
- c = UTF8Util::DecodeNextChar_Advance0(&buf);
- if (index == 0)
- return c;
- index--;
- }
-
- return c;
- }
-
- do
- {
- c = UTF8Util::DecodeNextChar_Advance0(&buf);
- index--;
-
- if (c == 0)
- {
- // We've hit the end of the string; don't go further.
- OVR_ASSERT(index == 0);
- return c;
- }
- } while (index >= 0);
-
- return c;
-}
-
-SPInt OVR_STDCALL GetByteIndex(SPInt index, const char *putf8str, SPInt length)
-{
- const char* buf = putf8str;
-
- if (length != -1)
- {
- while ((buf - putf8str) < length && index > 0)
- {
- UTF8Util::DecodeNextChar_Advance0(&buf);
- index--;
- }
-
- return buf-putf8str;
- }
-
- while (index > 0)
- {
- UInt32 c = UTF8Util::DecodeNextChar_Advance0(&buf);
- index--;
-
- if (c == 0)
- return buf-putf8str;
- };
-
- return buf-putf8str;
-}
-
-int OVR_STDCALL GetEncodeCharSize(UInt32 ucs_character)
-{
- if (ucs_character <= 0x7F)
- return 1;
- else if (ucs_character <= 0x7FF)
- return 2;
- else if (ucs_character <= 0xFFFF)
- return 3;
- else if (ucs_character <= 0x1FFFFF)
- return 4;
- else if (ucs_character <= 0x3FFFFFF)
- return 5;
- else if (ucs_character <= 0x7FFFFFFF)
- return 6;
- else
- return 0;
-}
-
-UInt32 OVR_STDCALL DecodeNextChar_Advance0(const char** putf8Buffer)
-{
- UInt32 uc;
- char c;
-
- // Security considerations:
- //
- // Changed, this is now only the case for DecodeNextChar:
- // - If we hit a zero byte, we want to return 0 without stepping
- // the buffer pointer past the 0. th
- //
- // If we hit an "overlong sequence"; i.e. a character encoded
- // in a longer multibyte string than is necessary, then we
- // need to discard the character. This is so attackers can't
- // disguise dangerous characters or character sequences --
- // there is only one valid encoding for each character.
- //
- // If we decode characters { 0xD800 .. 0xDFFF } or { 0xFFFE,
- // 0xFFFF } then we ignore them; they are not valid in UTF-8.
-
- // This isn't actually an invalid character; it's a valid char that
- // looks like an inverted question mark.
-#define INVALID_CHAR 0x0FFFD
-
-#define FIRST_BYTE(mask, shift) \
- uc = (c & (mask)) << (shift);
-
-#define NEXT_BYTE(shift) \
- c = **putf8Buffer; \
- if (c == 0) return 0; /* end of buffer, do not advance */ \
- if ((c & 0xC0) != 0x80) return INVALID_CHAR; /* standard check */ \
- (*putf8Buffer)++; \
- uc |= (c & 0x3F) << shift;
-
- c = **putf8Buffer;
- (*putf8Buffer)++;
- if (c == 0)
- return 0; // End of buffer.
-
- if ((c & 0x80) == 0) return (UInt32) c; // Conventional 7-bit ASCII.
-
- // Multi-byte sequences.
- if ((c & 0xE0) == 0xC0)
- {
- // Two-byte sequence.
- FIRST_BYTE(0x1F, 6);
- NEXT_BYTE(0);
- if (uc < 0x80) return INVALID_CHAR; // overlong
- return uc;
- }
- else if ((c & 0xF0) == 0xE0)
- {
- // Three-byte sequence.
- FIRST_BYTE(0x0F, 12);
- NEXT_BYTE(6);
- NEXT_BYTE(0);
- if (uc < 0x800) return INVALID_CHAR; // overlong
- // Not valid ISO 10646, but Flash requires these to work
- // see AS3 test e15_5_3_2_3 for String.fromCharCode().charCodeAt(0)
- // if (uc >= 0x0D800 && uc <= 0x0DFFF) return INVALID_CHAR;
- // if (uc == 0x0FFFE || uc == 0x0FFFF) return INVALID_CHAR; // not valid ISO 10646
- return uc;
- }
- else if ((c & 0xF8) == 0xF0)
- {
- // Four-byte sequence.
- FIRST_BYTE(0x07, 18);
- NEXT_BYTE(12);
- NEXT_BYTE(6);
- NEXT_BYTE(0);
- if (uc < 0x010000) return INVALID_CHAR; // overlong
- return uc;
- }
- else if ((c & 0xFC) == 0xF8)
- {
- // Five-byte sequence.
- FIRST_BYTE(0x03, 24);
- NEXT_BYTE(18);
- NEXT_BYTE(12);
- NEXT_BYTE(6);
- NEXT_BYTE(0);
- if (uc < 0x0200000) return INVALID_CHAR; // overlong
- return uc;
- }
- else if ((c & 0xFE) == 0xFC)
- {
- // Six-byte sequence.
- FIRST_BYTE(0x01, 30);
- NEXT_BYTE(24);
- NEXT_BYTE(18);
- NEXT_BYTE(12);
- NEXT_BYTE(6);
- NEXT_BYTE(0);
- if (uc < 0x04000000) return INVALID_CHAR; // overlong
- return uc;
- }
- else
- {
- // Invalid.
- return INVALID_CHAR;
- }
-}
-
-
-void OVR_STDCALL EncodeChar(char* pbuffer, SPInt* pindex, UInt32 ucs_character)
-{
- if (ucs_character <= 0x7F)
- {
- // Plain single-byte ASCII.
- pbuffer[(*pindex)++] = (char) ucs_character;
- }
- else if (ucs_character <= 0x7FF)
- {
- // Two bytes.
- pbuffer[(*pindex)++] = 0xC0 | (char)(ucs_character >> 6);
- pbuffer[(*pindex)++] = 0x80 | (char)((ucs_character >> 0) & 0x3F);
- }
- else if (ucs_character <= 0xFFFF)
- {
- // Three bytes.
- pbuffer[(*pindex)++] = 0xE0 | (char)(ucs_character >> 12);
- pbuffer[(*pindex)++] = 0x80 | (char)((ucs_character >> 6) & 0x3F);
- pbuffer[(*pindex)++] = 0x80 | (char)((ucs_character >> 0) & 0x3F);
- }
- else if (ucs_character <= 0x1FFFFF)
- {
- // Four bytes.
- pbuffer[(*pindex)++] = 0xF0 | (char)(ucs_character >> 18);
- pbuffer[(*pindex)++] = 0x80 | (char)((ucs_character >> 12) & 0x3F);
- pbuffer[(*pindex)++] = 0x80 | (char)((ucs_character >> 6) & 0x3F);
- pbuffer[(*pindex)++] = 0x80 | (char)((ucs_character >> 0) & 0x3F);
- }
- else if (ucs_character <= 0x3FFFFFF)
- {
- // Five bytes.
- pbuffer[(*pindex)++] = 0xF8 | (char)(ucs_character >> 24);
- pbuffer[(*pindex)++] = 0x80 | (char)((ucs_character >> 18) & 0x3F);
- pbuffer[(*pindex)++] = 0x80 | (char)((ucs_character >> 12) & 0x3F);
- pbuffer[(*pindex)++] = 0x80 | (char)((ucs_character >> 6) & 0x3F);
- pbuffer[(*pindex)++] = 0x80 | (char)((ucs_character >> 0) & 0x3F);
- }
- else if (ucs_character <= 0x7FFFFFFF)
- {
- // Six bytes.
- pbuffer[(*pindex)++] = 0xFC | (char)(ucs_character >> 30);
- pbuffer[(*pindex)++] = 0x80 | (char)((ucs_character >> 24) & 0x3F);
- pbuffer[(*pindex)++] = 0x80 | (char)((ucs_character >> 18) & 0x3F);
- pbuffer[(*pindex)++] = 0x80 | (char)((ucs_character >> 12) & 0x3F);
- pbuffer[(*pindex)++] = 0x80 | (char)((ucs_character >> 6) & 0x3F);
- pbuffer[(*pindex)++] = 0x80 | (char)((ucs_character >> 0) & 0x3F);
- }
- else
- {
- // Invalid char; don't encode anything.
- }
-}
-
-SPInt OVR_STDCALL GetEncodeStringSize(const wchar_t* pchar, SPInt length)
-{
- SPInt len = 0;
- if (length != -1)
- for (int i = 0; i < length; i++)
- {
- len += GetEncodeCharSize(pchar[i]);
- }
- else
- for (int i = 0;; i++)
- {
- if (pchar[i] == 0)
- return len;
- len += GetEncodeCharSize(pchar[i]);
- }
- return len;
-}
-
-void OVR_STDCALL EncodeString(char *pbuff, const wchar_t* pchar, SPInt length)
-{
- SPInt ofs = 0;
- if (length != -1)
- {
- for (int i = 0; i < length; i++)
- {
- EncodeChar(pbuff, &ofs, pchar[i]);
- }
- }
- else
- {
- for (int i = 0;; i++)
- {
- if (pchar[i] == 0)
- break;
- EncodeChar(pbuff, &ofs, pchar[i]);
- }
- }
- pbuff[ofs] = 0;
-}
-
-UPInt OVR_STDCALL DecodeString(wchar_t *pbuff, const char* putf8str, SPInt bytesLen)
-{
- wchar_t *pbegin = pbuff;
- if (bytesLen == -1)
- {
- while (1)
- {
- UInt32 ch = DecodeNextChar_Advance0(&putf8str);
- if (ch == 0)
- break;
- else if (ch >= 0xFFFF)
- ch = 0xFFFD;
- *pbuff++ = wchar_t(ch);
- }
- }
- else
- {
- const char* p = putf8str;
- while ((p - putf8str) < bytesLen)
- {
- UInt32 ch = DecodeNextChar_Advance0(&p);
- if (ch >= 0xFFFF)
- ch = 0xFFFD;
- *pbuff++ = wchar_t(ch);
- }
- }
-
- *pbuff = 0;
- return pbuff - pbegin;
-}
-
-
-#ifdef UTF8_UNIT_TEST
-
-// Compile this test case with something like:
-//
-// gcc utf8.cpp -g -I.. -DUTF8_UNIT_TEST -lstdc++ -o utf8_test
-//
-// or
-//
-// cl utf8.cpp -Zi -Od -DUTF8_UNIT_TEST -I..
-//
-// If possible, try running the test program with the first arg
-// pointing at the file:
-//
-// http://www.cl.cam.ac.uk/~mgk25/ucs/examples/UTF-8-test.txt
-//
-// and examine the results by eye to make sure they are acceptable to
-// you.
-
-
-#include "base/utility.h"
-#include <stdio.h>
-
-
-bool check_equal(const char* utf8_in, const UInt32* ucs_in)
-{
- for (;;)
- {
- UInt32 next_ucs = *ucs_in++;
- UInt32 next_ucs_from_utf8 = utf8::decode_next_unicode_character(&utf8_in);
- if (next_ucs != next_ucs_from_utf8)
- {
- return false;
- }
- if (next_ucs == 0)
- {
- OVR_ASSERT(next_ucs_from_utf8 == 0);
- break;
- }
- }
-
- return true;
-}
-
-
-void log_ascii(const char* line)
-{
- for (;;)
- {
- unsigned char c = (unsigned char) *line++;
- if (c == 0)
- {
- // End of line.
- return;
- }
- else if (c != '\n'
- && (c < 32 || c > 127))
- {
- // Non-printable as plain ASCII.
- printf("<0x%02X>", (int) c);
- }
- else
- {
- printf("%c", c);
- }
- }
-}
-
-
-void log_ucs(const UInt32* line)
-{
- for (;;)
- {
- UInt32 uc = *line++;
- if (uc == 0)
- {
- // End of line.
- return;
- }
- else if (uc != '\n'
- && (uc < 32 || uc > 127))
- {
- // Non-printable as plain ASCII.
- printf("<U-%04X>", uc);
- }
- else
- {
- printf("%c", (char) uc);
- }
- }
-}
-
-
-// Simple canned test.
-int main(int argc, const char* argv[])
-{
- {
- const char* test8 = "Ignacio Castaño";
- const UInt32 test32[] =
- {
- 0x49, 0x67, 0x6E, 0x61, 0x63,
- 0x69, 0x6F, 0x20, 0x43, 0x61,
- 0x73, 0x74, 0x61, 0xF1, 0x6F,
- 0x00
- };
-
- OVR_ASSERT(check_equal(test8, test32));
- }
-
- // If user passed an arg, try reading the file as UTF-8 encoded text.
- if (argc > 1)
- {
- const char* filename = argv[1];
- FILE* fp = fopen(filename, "rb");
- if (fp == NULL)
- {
- printf("Can't open file '%s'\n", filename);
- return 1;
- }
-
- // Read lines from the file, encode/decode them, and highlight discrepancies.
- const int LINE_SIZE = 200; // max line size
- char line_buffer_utf8[LINE_SIZE];
- char reencoded_utf8[6 * LINE_SIZE];
- UInt32 line_buffer_ucs[LINE_SIZE];
-
- int byte_counter = 0;
- for (;;)
- {
- int c = fgetc(fp);
- if (c == EOF)
- {
- // Done.
- break;
- }
- line_buffer_utf8[byte_counter++] = c;
- if (c == '\n' || byte_counter >= LINE_SIZE - 2)
- {
- // End of line. Process the line.
- line_buffer_utf8[byte_counter++] = 0; // terminate.
-
- // Decode into UCS.
- const char* p = line_buffer_utf8;
- UInt32* q = line_buffer_ucs;
- for (;;)
- {
- UInt32 uc = UTF8Util::DecodeNextChar(&p);
- *q++ = uc;
-
- OVR_ASSERT(q < line_buffer_ucs + LINE_SIZE);
- OVR_ASSERT(p < line_buffer_utf8 + LINE_SIZE);
-
- if (uc == 0) break;
- }
-
- // Encode back into UTF-8.
- q = line_buffer_ucs;
- int index = 0;
- for (;;)
- {
- UInt32 uc = *q++;
- OVR_ASSERT(index < LINE_SIZE * 6 - 6);
- int last_index = index;
- UTF8Util::EncodeChar(reencoded_utf8, &index, uc);
- OVR_ASSERT(index <= last_index + 6);
- if (uc == 0) break;
- }
-
- // This can be useful for debugging.
-#if 0
- // Show the UCS and the re-encoded UTF-8.
- log_ucs(line_buffer_ucs);
- log_ascii(reencoded_utf8);
-#endif // 0
-
- OVR_ASSERT(check_equal(line_buffer_utf8, line_buffer_ucs));
- OVR_ASSERT(check_equal(reencoded_utf8, line_buffer_ucs));
-
- // Start next line.
- byte_counter = 0;
- }
- }
-
- fclose(fp);
- }
-
- return 0;
-}
-
-
-#endif // UTF8_UNIT_TEST
-
-}} // namespace UTF8Util::OVR
-
+/**************************************************************************
+
+Filename : OVR_UTF8Util.cpp
+Content : UTF8 Unicode character encoding/decoding support
+Created : September 19, 2012
+Notes :
+Notes : Much useful info at "UTF-8 and Unicode FAQ"
+ http://www.cl.cam.ac.uk/~mgk25/unicode.html
+
+Copyright : Copyright 2012 Oculus VR, Inc. All Rights reserved.
+
+Use of this software is subject to the terms of the Oculus license
+agreement provided at the time of installation or download, or which
+otherwise accompanies this software in either electronic or hard copy form.
+
+************************************************************************************/
+
+#include "OVR_UTF8Util.h"
+
+namespace OVR { namespace UTF8Util {
+
+SPInt OVR_STDCALL GetLength(const char* buf, SPInt buflen)
+{
+ const char* p = buf;
+ SPInt length = 0;
+
+ if (buflen != -1)
+ {
+ while (p - buf < buflen)
+ {
+ // We should be able to have ASStrings with 0 in the middle.
+ UTF8Util::DecodeNextChar_Advance0(&p);
+ length++;
+ }
+ }
+ else
+ {
+ while (UTF8Util::DecodeNextChar_Advance0(&p))
+ length++;
+ }
+
+ return length;
+}
+
+UInt32 OVR_STDCALL GetCharAt(SPInt index, const char* putf8str, SPInt length)
+{
+ const char* buf = putf8str;
+ UInt32 c = 0;
+
+ if (length != -1)
+ {
+ while (buf - putf8str < length)
+ {
+ c = UTF8Util::DecodeNextChar_Advance0(&buf);
+ if (index == 0)
+ return c;
+ index--;
+ }
+
+ return c;
+ }
+
+ do
+ {
+ c = UTF8Util::DecodeNextChar_Advance0(&buf);
+ index--;
+
+ if (c == 0)
+ {
+ // We've hit the end of the string; don't go further.
+ OVR_ASSERT(index == 0);
+ return c;
+ }
+ } while (index >= 0);
+
+ return c;
+}
+
+SPInt OVR_STDCALL GetByteIndex(SPInt index, const char *putf8str, SPInt length)
+{
+ const char* buf = putf8str;
+
+ if (length != -1)
+ {
+ while ((buf - putf8str) < length && index > 0)
+ {
+ UTF8Util::DecodeNextChar_Advance0(&buf);
+ index--;
+ }
+
+ return buf-putf8str;
+ }
+
+ while (index > 0)
+ {
+ UInt32 c = UTF8Util::DecodeNextChar_Advance0(&buf);
+ index--;
+
+ if (c == 0)
+ return buf-putf8str;
+ };
+
+ return buf-putf8str;
+}
+
+int OVR_STDCALL GetEncodeCharSize(UInt32 ucs_character)
+{
+ if (ucs_character <= 0x7F)
+ return 1;
+ else if (ucs_character <= 0x7FF)
+ return 2;
+ else if (ucs_character <= 0xFFFF)
+ return 3;
+ else if (ucs_character <= 0x1FFFFF)
+ return 4;
+ else if (ucs_character <= 0x3FFFFFF)
+ return 5;
+ else if (ucs_character <= 0x7FFFFFFF)
+ return 6;
+ else
+ return 0;
+}
+
+UInt32 OVR_STDCALL DecodeNextChar_Advance0(const char** putf8Buffer)
+{
+ UInt32 uc;
+ char c;
+
+ // Security considerations:
+ //
+ // Changed, this is now only the case for DecodeNextChar:
+ // - If we hit a zero byte, we want to return 0 without stepping
+ // the buffer pointer past the 0. th
+ //
+ // If we hit an "overlong sequence"; i.e. a character encoded
+ // in a longer multibyte string than is necessary, then we
+ // need to discard the character. This is so attackers can't
+ // disguise dangerous characters or character sequences --
+ // there is only one valid encoding for each character.
+ //
+ // If we decode characters { 0xD800 .. 0xDFFF } or { 0xFFFE,
+ // 0xFFFF } then we ignore them; they are not valid in UTF-8.
+
+ // This isn't actually an invalid character; it's a valid char that
+ // looks like an inverted question mark.
+#define INVALID_CHAR 0x0FFFD
+
+#define FIRST_BYTE(mask, shift) \
+ uc = (c & (mask)) << (shift);
+
+#define NEXT_BYTE(shift) \
+ c = **putf8Buffer; \
+ if (c == 0) return 0; /* end of buffer, do not advance */ \
+ if ((c & 0xC0) != 0x80) return INVALID_CHAR; /* standard check */ \
+ (*putf8Buffer)++; \
+ uc |= (c & 0x3F) << shift;
+
+ c = **putf8Buffer;
+ (*putf8Buffer)++;
+ if (c == 0)
+ return 0; // End of buffer.
+
+ if ((c & 0x80) == 0) return (UInt32) c; // Conventional 7-bit ASCII.
+
+ // Multi-byte sequences.
+ if ((c & 0xE0) == 0xC0)
+ {
+ // Two-byte sequence.
+ FIRST_BYTE(0x1F, 6);
+ NEXT_BYTE(0);
+ if (uc < 0x80) return INVALID_CHAR; // overlong
+ return uc;
+ }
+ else if ((c & 0xF0) == 0xE0)
+ {
+ // Three-byte sequence.
+ FIRST_BYTE(0x0F, 12);
+ NEXT_BYTE(6);
+ NEXT_BYTE(0);
+ if (uc < 0x800) return INVALID_CHAR; // overlong
+ // Not valid ISO 10646, but Flash requires these to work
+ // see AS3 test e15_5_3_2_3 for String.fromCharCode().charCodeAt(0)
+ // if (uc >= 0x0D800 && uc <= 0x0DFFF) return INVALID_CHAR;
+ // if (uc == 0x0FFFE || uc == 0x0FFFF) return INVALID_CHAR; // not valid ISO 10646
+ return uc;
+ }
+ else if ((c & 0xF8) == 0xF0)
+ {
+ // Four-byte sequence.
+ FIRST_BYTE(0x07, 18);
+ NEXT_BYTE(12);
+ NEXT_BYTE(6);
+ NEXT_BYTE(0);
+ if (uc < 0x010000) return INVALID_CHAR; // overlong
+ return uc;
+ }
+ else if ((c & 0xFC) == 0xF8)
+ {
+ // Five-byte sequence.
+ FIRST_BYTE(0x03, 24);
+ NEXT_BYTE(18);
+ NEXT_BYTE(12);
+ NEXT_BYTE(6);
+ NEXT_BYTE(0);
+ if (uc < 0x0200000) return INVALID_CHAR; // overlong
+ return uc;
+ }
+ else if ((c & 0xFE) == 0xFC)
+ {
+ // Six-byte sequence.
+ FIRST_BYTE(0x01, 30);
+ NEXT_BYTE(24);
+ NEXT_BYTE(18);
+ NEXT_BYTE(12);
+ NEXT_BYTE(6);
+ NEXT_BYTE(0);
+ if (uc < 0x04000000) return INVALID_CHAR; // overlong
+ return uc;
+ }
+ else
+ {
+ // Invalid.
+ return INVALID_CHAR;
+ }
+}
+
+
+void OVR_STDCALL EncodeChar(char* pbuffer, SPInt* pindex, UInt32 ucs_character)
+{
+ if (ucs_character <= 0x7F)
+ {
+ // Plain single-byte ASCII.
+ pbuffer[(*pindex)++] = (char) ucs_character;
+ }
+ else if (ucs_character <= 0x7FF)
+ {
+ // Two bytes.
+ pbuffer[(*pindex)++] = 0xC0 | (char)(ucs_character >> 6);
+ pbuffer[(*pindex)++] = 0x80 | (char)((ucs_character >> 0) & 0x3F);
+ }
+ else if (ucs_character <= 0xFFFF)
+ {
+ // Three bytes.
+ pbuffer[(*pindex)++] = 0xE0 | (char)(ucs_character >> 12);
+ pbuffer[(*pindex)++] = 0x80 | (char)((ucs_character >> 6) & 0x3F);
+ pbuffer[(*pindex)++] = 0x80 | (char)((ucs_character >> 0) & 0x3F);
+ }
+ else if (ucs_character <= 0x1FFFFF)
+ {
+ // Four bytes.
+ pbuffer[(*pindex)++] = 0xF0 | (char)(ucs_character >> 18);
+ pbuffer[(*pindex)++] = 0x80 | (char)((ucs_character >> 12) & 0x3F);
+ pbuffer[(*pindex)++] = 0x80 | (char)((ucs_character >> 6) & 0x3F);
+ pbuffer[(*pindex)++] = 0x80 | (char)((ucs_character >> 0) & 0x3F);
+ }
+ else if (ucs_character <= 0x3FFFFFF)
+ {
+ // Five bytes.
+ pbuffer[(*pindex)++] = 0xF8 | (char)(ucs_character >> 24);
+ pbuffer[(*pindex)++] = 0x80 | (char)((ucs_character >> 18) & 0x3F);
+ pbuffer[(*pindex)++] = 0x80 | (char)((ucs_character >> 12) & 0x3F);
+ pbuffer[(*pindex)++] = 0x80 | (char)((ucs_character >> 6) & 0x3F);
+ pbuffer[(*pindex)++] = 0x80 | (char)((ucs_character >> 0) & 0x3F);
+ }
+ else if (ucs_character <= 0x7FFFFFFF)
+ {
+ // Six bytes.
+ pbuffer[(*pindex)++] = 0xFC | (char)(ucs_character >> 30);
+ pbuffer[(*pindex)++] = 0x80 | (char)((ucs_character >> 24) & 0x3F);
+ pbuffer[(*pindex)++] = 0x80 | (char)((ucs_character >> 18) & 0x3F);
+ pbuffer[(*pindex)++] = 0x80 | (char)((ucs_character >> 12) & 0x3F);
+ pbuffer[(*pindex)++] = 0x80 | (char)((ucs_character >> 6) & 0x3F);
+ pbuffer[(*pindex)++] = 0x80 | (char)((ucs_character >> 0) & 0x3F);
+ }
+ else
+ {
+ // Invalid char; don't encode anything.
+ }
+}
+
+SPInt OVR_STDCALL GetEncodeStringSize(const wchar_t* pchar, SPInt length)
+{
+ SPInt len = 0;
+ if (length != -1)
+ for (int i = 0; i < length; i++)
+ {
+ len += GetEncodeCharSize(pchar[i]);
+ }
+ else
+ for (int i = 0;; i++)
+ {
+ if (pchar[i] == 0)
+ return len;
+ len += GetEncodeCharSize(pchar[i]);
+ }
+ return len;
+}
+
+void OVR_STDCALL EncodeString(char *pbuff, const wchar_t* pchar, SPInt length)
+{
+ SPInt ofs = 0;
+ if (length != -1)
+ {
+ for (int i = 0; i < length; i++)
+ {
+ EncodeChar(pbuff, &ofs, pchar[i]);
+ }
+ }
+ else
+ {
+ for (int i = 0;; i++)
+ {
+ if (pchar[i] == 0)
+ break;
+ EncodeChar(pbuff, &ofs, pchar[i]);
+ }
+ }
+ pbuff[ofs] = 0;
+}
+
+UPInt OVR_STDCALL DecodeString(wchar_t *pbuff, const char* putf8str, SPInt bytesLen)
+{
+ wchar_t *pbegin = pbuff;
+ if (bytesLen == -1)
+ {
+ while (1)
+ {
+ UInt32 ch = DecodeNextChar_Advance0(&putf8str);
+ if (ch == 0)
+ break;
+ else if (ch >= 0xFFFF)
+ ch = 0xFFFD;
+ *pbuff++ = wchar_t(ch);
+ }
+ }
+ else
+ {
+ const char* p = putf8str;
+ while ((p - putf8str) < bytesLen)
+ {
+ UInt32 ch = DecodeNextChar_Advance0(&p);
+ if (ch >= 0xFFFF)
+ ch = 0xFFFD;
+ *pbuff++ = wchar_t(ch);
+ }
+ }
+
+ *pbuff = 0;
+ return pbuff - pbegin;
+}
+
+
+#ifdef UTF8_UNIT_TEST
+
+// Compile this test case with something like:
+//
+// gcc utf8.cpp -g -I.. -DUTF8_UNIT_TEST -lstdc++ -o utf8_test
+//
+// or
+//
+// cl utf8.cpp -Zi -Od -DUTF8_UNIT_TEST -I..
+//
+// If possible, try running the test program with the first arg
+// pointing at the file:
+//
+// http://www.cl.cam.ac.uk/~mgk25/ucs/examples/UTF-8-test.txt
+//
+// and examine the results by eye to make sure they are acceptable to
+// you.
+
+
+#include "base/utility.h"
+#include <stdio.h>
+
+
+bool check_equal(const char* utf8_in, const UInt32* ucs_in)
+{
+ for (;;)
+ {
+ UInt32 next_ucs = *ucs_in++;
+ UInt32 next_ucs_from_utf8 = utf8::decode_next_unicode_character(&utf8_in);
+ if (next_ucs != next_ucs_from_utf8)
+ {
+ return false;
+ }
+ if (next_ucs == 0)
+ {
+ OVR_ASSERT(next_ucs_from_utf8 == 0);
+ break;
+ }
+ }
+
+ return true;
+}
+
+
+void log_ascii(const char* line)
+{
+ for (;;)
+ {
+ unsigned char c = (unsigned char) *line++;
+ if (c == 0)
+ {
+ // End of line.
+ return;
+ }
+ else if (c != '\n'
+ && (c < 32 || c > 127))
+ {
+ // Non-printable as plain ASCII.
+ printf("<0x%02X>", (int) c);
+ }
+ else
+ {
+ printf("%c", c);
+ }
+ }
+}
+
+
+void log_ucs(const UInt32* line)
+{
+ for (;;)
+ {
+ UInt32 uc = *line++;
+ if (uc == 0)
+ {
+ // End of line.
+ return;
+ }
+ else if (uc != '\n'
+ && (uc < 32 || uc > 127))
+ {
+ // Non-printable as plain ASCII.
+ printf("<U-%04X>", uc);
+ }
+ else
+ {
+ printf("%c", (char) uc);
+ }
+ }
+}
+
+
+// Simple canned test.
+int main(int argc, const char* argv[])
+{
+ {
+ const char* test8 = "Ignacio Castaño";
+ const UInt32 test32[] =
+ {
+ 0x49, 0x67, 0x6E, 0x61, 0x63,
+ 0x69, 0x6F, 0x20, 0x43, 0x61,
+ 0x73, 0x74, 0x61, 0xF1, 0x6F,
+ 0x00
+ };
+
+ OVR_ASSERT(check_equal(test8, test32));
+ }
+
+ // If user passed an arg, try reading the file as UTF-8 encoded text.
+ if (argc > 1)
+ {
+ const char* filename = argv[1];
+ FILE* fp = fopen(filename, "rb");
+ if (fp == NULL)
+ {
+ printf("Can't open file '%s'\n", filename);
+ return 1;
+ }
+
+ // Read lines from the file, encode/decode them, and highlight discrepancies.
+ const int LINE_SIZE = 200; // max line size
+ char line_buffer_utf8[LINE_SIZE];
+ char reencoded_utf8[6 * LINE_SIZE];
+ UInt32 line_buffer_ucs[LINE_SIZE];
+
+ int byte_counter = 0;
+ for (;;)
+ {
+ int c = fgetc(fp);
+ if (c == EOF)
+ {
+ // Done.
+ break;
+ }
+ line_buffer_utf8[byte_counter++] = c;
+ if (c == '\n' || byte_counter >= LINE_SIZE - 2)
+ {
+ // End of line. Process the line.
+ line_buffer_utf8[byte_counter++] = 0; // terminate.
+
+ // Decode into UCS.
+ const char* p = line_buffer_utf8;
+ UInt32* q = line_buffer_ucs;
+ for (;;)
+ {
+ UInt32 uc = UTF8Util::DecodeNextChar(&p);
+ *q++ = uc;
+
+ OVR_ASSERT(q < line_buffer_ucs + LINE_SIZE);
+ OVR_ASSERT(p < line_buffer_utf8 + LINE_SIZE);
+
+ if (uc == 0) break;
+ }
+
+ // Encode back into UTF-8.
+ q = line_buffer_ucs;
+ int index = 0;
+ for (;;)
+ {
+ UInt32 uc = *q++;
+ OVR_ASSERT(index < LINE_SIZE * 6 - 6);
+ int last_index = index;
+ UTF8Util::EncodeChar(reencoded_utf8, &index, uc);
+ OVR_ASSERT(index <= last_index + 6);
+ if (uc == 0) break;
+ }
+
+ // This can be useful for debugging.
+#if 0
+ // Show the UCS and the re-encoded UTF-8.
+ log_ucs(line_buffer_ucs);
+ log_ascii(reencoded_utf8);
+#endif // 0
+
+ OVR_ASSERT(check_equal(line_buffer_utf8, line_buffer_ucs));
+ OVR_ASSERT(check_equal(reencoded_utf8, line_buffer_ucs));
+
+ // Start next line.
+ byte_counter = 0;
+ }
+ }
+
+ fclose(fp);
+ }
+
+ return 0;
+}
+
+
+#endif // UTF8_UNIT_TEST
+
+}} // namespace UTF8Util::OVR
+
diff --git a/LibOVR/Src/Kernel/OVR_UTF8Util.h b/LibOVR/Src/Kernel/OVR_UTF8Util.h
index bf5af46..5448b96 100644
--- a/LibOVR/Src/Kernel/OVR_UTF8Util.h
+++ b/LibOVR/Src/Kernel/OVR_UTF8Util.h
@@ -1,88 +1,88 @@
-/************************************************************************************
-
-PublicHeader: OVR.h
-Filename : OVR_UTF8Util.h
-Content : UTF8 Unicode character encoding/decoding support
-Created : September 19, 2012
-Notes :
-
-Copyright : Copyright 2012 Oculus VR, Inc. All Rights reserved.
-
-Use of this software is subject to the terms of the Oculus license
-agreement provided at the time of installation or download, or which
-otherwise accompanies this software in either electronic or hard copy form.
-
-************************************************************************************/
-
-#ifndef OVR_UTF8Util_h
-#define OVR_UTF8Util_h
-
-#include "OVR_Types.h"
-
-namespace OVR { namespace UTF8Util {
-
-//-----------------------------------------------------------------------------------
-
-// *** UTF8 string length and indexing.
-
-// Determines the length of UTF8 string in characters.
-// If source length is specified (in bytes), null 0 character is counted properly.
-SPInt OVR_STDCALL GetLength(const char* putf8str, SPInt length = -1);
-
-// Gets a decoded UTF8 character at index; you can access up to the index returned
-// by GetLength. 0 will be returned for out of bounds access.
-UInt32 OVR_STDCALL GetCharAt(SPInt index, const char* putf8str, SPInt length = -1);
-
-// Converts UTF8 character index into byte offset.
-// -1 is returned if index was out of bounds.
-SPInt OVR_STDCALL GetByteIndex(SPInt index, const char* putf8str, SPInt length = -1);
-
-
-// *** 16-bit Unicode string Encoding/Decoding routines.
-
-// Determines the number of bytes necessary to encode a string.
-// Does not count the terminating 0 (null) character.
-SPInt OVR_STDCALL GetEncodeStringSize(const wchar_t* pchar, SPInt length = -1);
-
-// Encodes a unicode (UCS-2 only) string into a buffer. The size of buffer must be at
-// least GetEncodeStringSize() + 1.
-void OVR_STDCALL EncodeString(char *pbuff, const wchar_t* pchar, SPInt length = -1);
-
-// Decode UTF8 into a wchar_t buffer. Must have GetLength()+1 characters available.
-// Characters over 0xFFFF are replaced with 0xFFFD.
-// Returns the length of resulting string (number of characters)
-UPInt OVR_STDCALL DecodeString(wchar_t *pbuff, const char* putf8str, SPInt bytesLen = -1);
-
-
-// *** Individual character Encoding/Decoding.
-
-// Determined the number of bytes necessary to encode a UCS character.
-int OVR_STDCALL GetEncodeCharSize(UInt32 ucsCharacter);
-
-// Encodes the given UCS character into the given UTF-8 buffer.
-// Writes the data starting at buffer[offset], and
-// increments offset by the number of bytes written.
-// May write up to 6 bytes, so make sure there's room in the buffer
-void OVR_STDCALL EncodeChar(char* pbuffer, SPInt* poffset, UInt32 ucsCharacter);
-
-// Return the next Unicode character in the UTF-8 encoded buffer.
-// Invalid UTF-8 sequences produce a U+FFFD character as output.
-// Advances *utf8_buffer past the character returned. Pointer advance
-// occurs even if the terminating 0 character is hit, since that allows
-// strings with middle '\0' characters to be supported.
-UInt32 OVR_STDCALL DecodeNextChar_Advance0(const char** putf8Buffer);
-
-// Safer version of DecodeNextChar, which doesn't advance pointer if
-// null character is hit.
-inline UInt32 DecodeNextChar(const char** putf8Buffer)
-{
- UInt32 ch = DecodeNextChar_Advance0(putf8Buffer);
- if (ch == 0)
- (*putf8Buffer)--;
- return ch;
-}
-
-
-}} // OVR::UTF8Util
-
-#endif
+/************************************************************************************
+
+PublicHeader: OVR.h
+Filename : OVR_UTF8Util.h
+Content : UTF8 Unicode character encoding/decoding support
+Created : September 19, 2012
+Notes :
+
+Copyright : Copyright 2012 Oculus VR, Inc. All Rights reserved.
+
+Use of this software is subject to the terms of the Oculus license
+agreement provided at the time of installation or download, or which
+otherwise accompanies this software in either electronic or hard copy form.
+
+************************************************************************************/
+
+#ifndef OVR_UTF8Util_h
+#define OVR_UTF8Util_h
+
+#include "OVR_Types.h"
+
+namespace OVR { namespace UTF8Util {
+
+//-----------------------------------------------------------------------------------
+
+// *** UTF8 string length and indexing.
+
+// Determines the length of UTF8 string in characters.
+// If source length is specified (in bytes), null 0 character is counted properly.
+SPInt OVR_STDCALL GetLength(const char* putf8str, SPInt length = -1);
+
+// Gets a decoded UTF8 character at index; you can access up to the index returned
+// by GetLength. 0 will be returned for out of bounds access.
+UInt32 OVR_STDCALL GetCharAt(SPInt index, const char* putf8str, SPInt length = -1);
+
+// Converts UTF8 character index into byte offset.
+// -1 is returned if index was out of bounds.
+SPInt OVR_STDCALL GetByteIndex(SPInt index, const char* putf8str, SPInt length = -1);
+
+
+// *** 16-bit Unicode string Encoding/Decoding routines.
+
+// Determines the number of bytes necessary to encode a string.
+// Does not count the terminating 0 (null) character.
+SPInt OVR_STDCALL GetEncodeStringSize(const wchar_t* pchar, SPInt length = -1);
+
+// Encodes a unicode (UCS-2 only) string into a buffer. The size of buffer must be at
+// least GetEncodeStringSize() + 1.
+void OVR_STDCALL EncodeString(char *pbuff, const wchar_t* pchar, SPInt length = -1);
+
+// Decode UTF8 into a wchar_t buffer. Must have GetLength()+1 characters available.
+// Characters over 0xFFFF are replaced with 0xFFFD.
+// Returns the length of resulting string (number of characters)
+UPInt OVR_STDCALL DecodeString(wchar_t *pbuff, const char* putf8str, SPInt bytesLen = -1);
+
+
+// *** Individual character Encoding/Decoding.
+
+// Determined the number of bytes necessary to encode a UCS character.
+int OVR_STDCALL GetEncodeCharSize(UInt32 ucsCharacter);
+
+// Encodes the given UCS character into the given UTF-8 buffer.
+// Writes the data starting at buffer[offset], and
+// increments offset by the number of bytes written.
+// May write up to 6 bytes, so make sure there's room in the buffer
+void OVR_STDCALL EncodeChar(char* pbuffer, SPInt* poffset, UInt32 ucsCharacter);
+
+// Return the next Unicode character in the UTF-8 encoded buffer.
+// Invalid UTF-8 sequences produce a U+FFFD character as output.
+// Advances *utf8_buffer past the character returned. Pointer advance
+// occurs even if the terminating 0 character is hit, since that allows
+// strings with middle '\0' characters to be supported.
+UInt32 OVR_STDCALL DecodeNextChar_Advance0(const char** putf8Buffer);
+
+// Safer version of DecodeNextChar, which doesn't advance pointer if
+// null character is hit.
+inline UInt32 DecodeNextChar(const char** putf8Buffer)
+{
+ UInt32 ch = DecodeNextChar_Advance0(putf8Buffer);
+ if (ch == 0)
+ (*putf8Buffer)--;
+ return ch;
+}
+
+
+}} // OVR::UTF8Util
+
+#endif
diff --git a/LibOVR/Src/OVR_Device.h b/LibOVR/Src/OVR_Device.h
index 4434916..72a8c5e 100644
--- a/LibOVR/Src/OVR_Device.h
+++ b/LibOVR/Src/OVR_Device.h
@@ -1,627 +1,619 @@
-/************************************************************************************
-
-PublicHeader: OVR.h
-Filename : OVR_Device.h
-Content : Definition of HMD-related Device interfaces
-Created : September 21, 2012
-Authors : Michael Antonov
-
-Copyright : Copyright 2012 Oculus VR, Inc. All Rights reserved.
-
-Use of this software is subject to the terms of the Oculus license
-agreement provided at the time of installation or download, or which
-otherwise accompanies this software in either electronic or hard copy form.
-
-*************************************************************************************/
-
-#ifndef OVR_Device_h
-#define OVR_Device_h
-
-#include "OVR_DeviceConstants.h"
-#include "OVR_DeviceHandle.h"
-#include "OVR_DeviceMessages.h"
-#include "OVR_HIDDeviceBase.h"
-
-#include "Kernel/OVR_Atomic.h"
-#include "Kernel/OVR_RefCount.h"
-#include "Kernel/OVR_String.h"
-
-namespace OVR {
-
-class SensorDevice;
-class DeviceCommon;
-class DeviceManager;
-
-// MessageHandler is a base class from which users derive to receive messages,
-// its OnMessage handler will be called for messages once it is installed on
-// a device. Same message handler can be installed on multiple devices.
-class MessageHandler
-{
- friend class MessageHandlerImpl;
-public:
- MessageHandler();
- virtual ~MessageHandler();
-
- // Returns 'true' if handler is currently installed on any devices.
- bool IsHandlerInstalled() const;
-
- // Should be called from derived class destructor to avoid handler
- // being called after it exits.
- void RemoveHandlerFromDevices();
-
- // Returns a pointer to the internal lock object that is locked by a
- // background thread while OnMessage() is called.
- // This lock guaranteed to survive until ~MessageHandler.
- Lock* GetHandlerLock() const;
-
-
- virtual void OnMessage(const Message&) { }
-
- // Determines if handler supports a specific message type. Can
- // be used to filter out entire message groups. The result
- // returned by this function shouldn't change after handler creation.
- virtual bool SupportsMessageType(MessageType) const { return true; }
-
-private:
- UPInt Internal[4];
-};
-
-
-//-------------------------------------------------------------------------------------
-// ***** DeviceBase
-
-// DeviceBase is the base class for all OVR Devices. It provides the following basic
-// functionality:
-// - Reports device type, manager, and associated parent (if any).
-// - Supports installable message handlers, which are notified of device events.
-// - Device objects are created through DeviceHandle::CreateDevice or more commonly
-// through DeviceEnumerator<>::CreateDevice.
-// - Created devices are reference counted, starting with RefCount of 1.
-// - Device is resources are cleaned up when it is Released, although its handles
-// may survive longer if referenced.
-
-class DeviceBase : public NewOverrideBase
-{
- friend class DeviceHandle;
- friend class DeviceManagerImpl;
-public:
-
- // Enumerating DeviceBase enumerates all devices.
- enum { EnumDeviceType = Device_All };
-
- virtual ~DeviceBase() { }
- virtual void AddRef();
- virtual void Release();
-
- virtual DeviceBase* GetParent() const;
- virtual DeviceManager* GetManager() const;
-
- virtual void SetMessageHandler(MessageHandler* handler);
- virtual MessageHandler* GetMessageHandler() const;
-
- virtual DeviceType GetType() const;
- virtual bool GetDeviceInfo(DeviceInfo* info) const;
-
- // returns the MessageHandler's lock
- Lock* GetHandlerLock() const;
-protected:
- // Internal
- virtual DeviceCommon* getDeviceCommon() const = 0;
-};
-
-
-//-------------------------------------------------------------------------------------
-// ***** DeviceInfo
-
-// DeviceInfo describes a device and its capabilities, obtained by calling
-// GetDeviceInfo. This base class only contains device-independent functionality;
-// users will normally use a derived HMDInfo or SensorInfo classes for more
-// extensive device info.
-
-class DeviceInfo
-{
-public:
- DeviceInfo() : InfoClassType(Device_None), Type(Device_None), Version(0)
- { ProductName[0] = Manufacturer[0] = 0; }
-
- enum { MaxNameLength = 32 };
-
- // Type of device for which DeviceInfo is intended.
- // This will be set to Device_HMD for HMDInfo structure, note that this may be
- // different form the actual device type since (Device_None) is valid.
- const DeviceType InfoClassType;
- // Type of device this describes. This must be the same as InfoClassType when
- // InfoClassType != Device_None.
- DeviceType Type;
- // Name string describing the product: "Oculus Rift DK1", etc.
- char ProductName[MaxNameLength];
- char Manufacturer[MaxNameLength];
- unsigned Version;
-
-protected:
- DeviceInfo(DeviceType type) : InfoClassType(type), Type(type), Version(0)
- { ProductName[0] = Manufacturer[0] = 0; }
- void operator = (const DeviceInfo&) { OVR_ASSERT(0); } // Assignment not allowed.
-};
-
-
-//-------------------------------------------------------------------------------------
-// DeviceEnumerationArgs provides device enumeration argumenrs for DeviceManager::EnumerateDevicesEx.
-class DeviceEnumerationArgs
-{
-public:
- DeviceEnumerationArgs(DeviceType enumType, bool availableOnly)
- : EnumType(enumType), AvailableOnly(availableOnly)
- { }
-
- // Helper; returns true if args match our enumeration criteria.
- bool MatchRule(DeviceType type, bool available) const
- {
- return ((EnumType == type) || (EnumType == Device_All)) &&
- (available || !AvailableOnly);
- }
-
-protected:
- DeviceType EnumType;
- bool AvailableOnly;
-};
-
-
-// DeviceEnumerator<> is used to enumerate and create devices of specified class,
-// it is returned by calling MeviceManager::EnumerateDevices. Initially, the enumerator will
-// refer to the first device of specified type. Additional devices can be accessed by
-// calling Next().
-
-template<class T = DeviceBase>
-class DeviceEnumerator : public DeviceHandle
-{
- friend class DeviceManager;
- friend class DeviceManagerImpl;
-public:
- DeviceEnumerator()
- : DeviceHandle(), EnumArgs(Device_None, true) { }
-
- // Next advances enumeration to the next device that first criteria.
- // Returns false if no more devices exist that match enumeration criteria.
- bool Next() { return enumerateNext(EnumArgs); }
-
- // Creates an instance of the device referenced by enumerator; returns null
- // if enumerator does not refer to a valid device or device is unavailable.
- // If device was already created, the same object with incremented ref-count is returned.
- T* CreateDevice() { return static_cast<T*>(DeviceHandle::CreateDevice()); }
-
-protected:
- DeviceEnumerator(const DeviceHandle &dev, const DeviceEnumerationArgs& args)
- : DeviceHandle(dev), EnumArgs(args)
- { }
-
- DeviceEnumerationArgs EnumArgs;
-};
-
-//-------------------------------------------------------------------------------------
-// ***** DeviceManager
-
-// DeviceManager maintains and provides access to devices supported by OVR, such as
-// HMDs and sensors. A single instance of DeviceManager is normally created at
-// program startup, allowing devices to be enumerated and created. DeviceManager is
-// reference counted and is AddRefed by its created child devices, causing it to
-// always be the last object that is released.
-//
-// Install MessageHandler on DeviceManager to detect when devices are inserted or removed.
-//
-// The following code will create the manager and its first available HMDDevice,
-// and then release it when not needed:
-//
-// DeviceManager* manager = DeviceManager::Create();
-// HMDDevice* hmd = manager->EnumerateDevices<HMDDevice>().CreateDevice();
-//
-// if (hmd) hmd->Release();
-// if (manager) manager->Release();
-
-
-class DeviceManager : public DeviceBase
-{
-public:
-
- DeviceManager()
- { }
-
- // DeviceBase implementation.
- virtual DeviceType GetType() const { return Device_Manager; }
- virtual DeviceManager* GetManager() const { return const_cast<DeviceManager*>(this); }
-
-
- // EnumerateDevices enumerates all of the available devices of the specified class,
- // returning an enumerator that references the first device. An empty enumerator is
- // returned if no devices are available. The following APIs are exposed through
- // DeviceEnumerator:
- // DeviceEnumerator::GetType() - Check device type. Returns Device_None
- // if no device was found/pointed to.
- // DeviceEnumerator::GetDeviceInfo() - Get more information on device.
- // DeviceEnumerator::CreateDevice() - Create an instance of device.
- // DeviceEnumerator::Next() - Move onto next device.
- template<class D>
- DeviceEnumerator<D> EnumerateDevices(bool availableOnly = true)
- {
- // TBD: A cleaner (but less efficient) alternative is though enumeratorFromHandle.
- DeviceEnumerator<> e = EnumerateDevicesEx(DeviceEnumerationArgs((DeviceType)D::EnumDeviceType, availableOnly));
- return *reinterpret_cast<DeviceEnumerator<D>*>(&e);
- }
-
- // EnumerateDevicesEx provides internal implementation for device enumeration, enumerating
- // devices based on dynamically specified DeviceType in DeviceEnumerationArgs.
- // End users should call DeumerateDevices<>() instead.
- virtual DeviceEnumerator<> EnumerateDevicesEx(const DeviceEnumerationArgs& args) = 0;
-
- // Adds a device (DeviceCreateDesc*) into Devices. Returns NULL,
- // if unsuccessful or device is already in the list.
- virtual Ptr<DeviceCreateDesc> AddDevice_NeedsLock(const DeviceCreateDesc& createDesc) = 0;
-
- // Creates a new DeviceManager. Only one instance of DeviceManager should be created at a time.
- static DeviceManager* Create();
-
- // Static constant for this device type, used in template cast type checks.
- enum { EnumDeviceType = Device_Manager };
-
-protected:
- DeviceEnumerator<> enumeratorFromHandle(const DeviceHandle& h, const DeviceEnumerationArgs& args)
- { return DeviceEnumerator<>(h, args); }
-
- DeviceManager* getThis() { return this; }
-};
-
-
-
-//-------------------------------------------------------------------------------------
-// ***** HMDInfo
-
-// This structure describes various aspects of the HMD allowing us to configure rendering.
-//
-// Currently included data:
-// - Physical screen dimensions, resolution, and eye distances.
-// (some of these will be configurable with a tool in the future).
-// These arguments allow us to properly setup projection across HMDs.
-// - DisplayDeviceName for identifying HMD screen; system-specific interpretation.
-//
-// TBD:
-// - Power on/ off?
-// - Sensor rates and capabilities
-// - Distortion radius/variables
-// - Screen update frequency
-// - Distortion needed flag
-// - Update modes:
-// Set update mode: Stereo (both sides together), mono (same in both eyes),
-// Alternating, Alternating scan-lines.
-
-class HMDInfo : public DeviceInfo
-{
-public:
- // Size of the entire screen, in pixels.
- unsigned HResolution, VResolution;
- // Physical dimensions of the active screen in meters. Can be used to calculate
- // projection center while considering IPD.
- float HScreenSize, VScreenSize;
- // Physical offset from the top of the screen to the eye center, in meters.
- // This will usually, but not necessarily be half of VScreenSize.
- float VScreenCenter;
- // Distance from the eye to screen surface, in meters.
- // Useful for calculating FOV and projection.
- float EyeToScreenDistance;
- // Distance between physical lens centers useful for calculating distortion center.
- float LensSeparationDistance;
- // Configured distance between the user's eye centers, in meters. Defaults to 0.064.
- float InterpupillaryDistance;
-
- // Radial distortion correction coefficients.
- // The distortion assumes that the input texture coordinates will be scaled
- // by the following equation:
- // uvResult = uvInput * (K0 + K1 * uvLength^2 + K2 * uvLength^4)
- // Where uvInput is the UV vector from the center of distortion in direction
- // of the mapped pixel, uvLength is the magnitude of that vector, and uvResult
- // the corresponding location after distortion.
- float DistortionK[4];
-
- float ChromaAbCorrection[4];
-
- // Desktop coordinate position of the screen (can be negative; may not be present on all platforms)
- int DesktopX, DesktopY;
-
- // Windows:
- // "\\\\.\\DISPLAY3", etc. Can be used in EnumDisplaySettings/CreateDC.
- char DisplayDeviceName[32];
-
- // MacOS:
- long DisplayId;
-
-
- HMDInfo()
- : DeviceInfo(Device_HMD),
- HResolution(0), VResolution(0), HScreenSize(0), VScreenSize(0),
- VScreenCenter(0), EyeToScreenDistance(0),
- LensSeparationDistance(0), InterpupillaryDistance(0),
- DesktopX(0), DesktopY(0), DisplayId(0)
- {
- DisplayDeviceName[0] = 0;
- memset(DistortionK, 0, sizeof(DistortionK));
- DistortionK[0] = 1;
- ChromaAbCorrection[0] = ChromaAbCorrection[2] = 1;
- ChromaAbCorrection[1] = ChromaAbCorrection[3] = 0;
- }
-
- // Operator = copies local fields only (base class must be correct already)
- void operator = (const HMDInfo& src)
- {
- HResolution = src.HResolution;
- VResolution = src.VResolution;
- HScreenSize = src.HScreenSize;
- VScreenSize = src.VScreenSize;
- VScreenCenter = src.VScreenCenter;
- EyeToScreenDistance = src.EyeToScreenDistance;
- LensSeparationDistance = src.LensSeparationDistance;
- InterpupillaryDistance = src.InterpupillaryDistance;
- DistortionK[0] = src.DistortionK[0];
- DistortionK[1] = src.DistortionK[1];
- DistortionK[2] = src.DistortionK[2];
- DistortionK[3] = src.DistortionK[3];
- ChromaAbCorrection[0] = src.ChromaAbCorrection[0];
- ChromaAbCorrection[1] = src.ChromaAbCorrection[1];
- ChromaAbCorrection[2] = src.ChromaAbCorrection[2];
- ChromaAbCorrection[3] = src.ChromaAbCorrection[3];
- DesktopX = src.DesktopX;
- DesktopY = src.DesktopY;
- memcpy(DisplayDeviceName, src.DisplayDeviceName, sizeof(DisplayDeviceName));
- DisplayId = src.DisplayId;
- }
-
- bool IsSameDisplay(const HMDInfo& o) const
- {
- return DisplayId == o.DisplayId &&
- String::CompareNoCase(DisplayDeviceName,
- o.DisplayDeviceName) == 0;
- }
-
-};
-
-
-// HMDDevice represents an Oculus HMD device unit. An instance of this class
-// is typically created from the DeviceManager.
-// After HMD device is created, we its sensor data can be obtained by
-// first creating a Sensor object and then.
-
-// TBD:
-// - Configure Sensor
-// - APIs to set On-Screen message, other states?
-
-class HMDDevice : public DeviceBase
-{
-public:
- HMDDevice()
- { }
-
- // Static constant for this device type, used in template cast type checks.
- enum { EnumDeviceType = Device_HMD };
-
- virtual DeviceType GetType() const { return Device_HMD; }
-
- // Creates a sensor associated with this HMD.
- virtual SensorDevice* GetSensor() = 0;
-
- // Disconnects from real HMD device. This HMDDevice remains as 'fake' HMD.
- // SensorDevice ptr is used to restore the 'fake' HMD (can be NULL).
- HMDDevice* Disconnect(SensorDevice*);
-
- // Returns 'true' if HMD device is a 'fake' HMD (was created this way or
- // 'Disconnect' method was called).
- bool IsDisconnected() const;
-};
-
-
-//-------------------------------------------------------------------------------------
-// ***** SensorRange & SensorInfo
-
-// SensorRange specifies maximum value ranges that SensorDevice hardware is configured
-// to detect. Although this range doesn't affect the scale of MessageBodyFrame values,
-// physical motions whose positive or negative magnitude is outside the specified range
-// may get clamped or misreported. Setting lower values may result in higher precision
-// tracking.
-struct SensorRange
-{
- SensorRange(float maxAcceleration = 0.0f, float maxRotationRate = 0.0f,
- float maxMagneticField = 0.0f)
- : MaxAcceleration(maxAcceleration), MaxRotationRate(maxRotationRate),
- MaxMagneticField(maxMagneticField)
- { }
-
- // Maximum detected acceleration in m/s^2. Up to 8*G equivalent support guaranteed,
- // where G is ~9.81 m/s^2.
- // Oculus DK1 HW has thresholds near: 2, 4 (default), 8, 16 G.
- float MaxAcceleration;
- // Maximum detected angular velocity in rad/s. Up to 8*Pi support guaranteed.
- // Oculus DK1 HW thresholds near: 1, 2, 4, 8 Pi (default).
- float MaxRotationRate;
- // Maximum detectable Magnetic field strength in Gauss. Up to 2.5 Gauss support guaranteed.
- // Oculus DK1 HW thresholds near: 0.88, 1.3, 1.9, 2.5 gauss.
- float MaxMagneticField;
-};
-
-// SensorInfo describes capabilities of the sensor device.
-class SensorInfo : public DeviceInfo
-{
-public:
- SensorInfo() : DeviceInfo(Device_Sensor), VendorId(0), ProductId(0)
- {
- SerialNumber[0] = 0;
- }
-
- // HID Vendor and ProductId of the device.
- UInt16 VendorId;
- UInt16 ProductId;
- // MaxRanges report maximum sensor range values supported by HW.
- SensorRange MaxRanges;
- // Sensor (and display) serial number.
- char SerialNumber[20];
-
-private:
- void operator = (const SensorInfo&) { OVR_ASSERT(0); } // Assignment not allowed.
-};
-
-
-//-------------------------------------------------------------------------------------
-// ***** SensorDevice
-
-// SensorDevice is an interface to sensor data.
-// Install a MessageHandler of SensorDevice instance to receive MessageBodyFrame
-// notifications.
-//
-// TBD: Add Polling API? More HID interfaces?
-
-class SensorDevice : public HIDDeviceBase, public DeviceBase
-{
-public:
- SensorDevice()
- { }
-
- // Static constant for this device type, used in template cast type checks.
- enum { EnumDeviceType = Device_Sensor };
-
- virtual DeviceType GetType() const { return Device_Sensor; }
-
-
- // CoordinateFrame defines whether messages come in the coordinate frame
- // of the sensor device or HMD, which has a different internal sensor.
- // Sensors obtained form the HMD will automatically use HMD coordinates.
- enum CoordinateFrame
- {
- Coord_Sensor = 0,
- Coord_HMD = 1
- };
-
- virtual void SetCoordinateFrame(CoordinateFrame coordframe) = 0;
- virtual CoordinateFrame GetCoordinateFrame() const = 0;
-
- // Sets report rate (in Hz) of MessageBodyFrame messages (delivered through MessageHandler::OnMessage call).
- // Currently supported maximum rate is 1000Hz. If the rate is set to 500 or 333 Hz then OnMessage will be
- // called twice or thrice at the same 'tick'.
- // If the rate is < 333 then the OnMessage / MessageBodyFrame will be called three
- // times for each 'tick': the first call will contain averaged values, the second
- // and third calls will provide with most recent two recorded samples.
- virtual void SetReportRate(unsigned rateHz) = 0;
- // Returns currently set report rate, in Hz. If 0 - error occurred.
- // Note, this value may be different from the one provided for SetReportRate. The return
- // value will contain the actual rate.
- virtual unsigned GetReportRate() const = 0;
-
- // Sets maximum range settings for the sensor described by SensorRange.
- // The function will fail if you try to pass values outside Maximum supported
- // by the HW, as described by SensorInfo.
- // Pass waitFlag == true to wait for command completion. For waitFlag == true,
- // returns true if the range was applied successfully (no HW error).
- // For waitFlag = false, return 'true' means that command was enqueued successfully.
- virtual bool SetRange(const SensorRange& range, bool waitFlag = false) = 0;
-
- // Return the current sensor range settings for the device. These may not exactly
- // match the values applied through SetRange.
- virtual void GetRange(SensorRange* range) const = 0;
-};
-
-//-------------------------------------------------------------------------------------
-// ***** LatencyTestConfiguration
-// LatencyTestConfiguration specifies configuration information for the Oculus Latency Tester device.
-struct LatencyTestConfiguration
-{
- LatencyTestConfiguration(const Color& threshold, bool sendSamples = false)
- : Threshold(threshold), SendSamples(sendSamples)
- {
- }
-
- // The color threshold for triggering a detected display change.
- Color Threshold;
- // Flag specifying whether we wish to receive a stream of color values from the sensor.
- bool SendSamples;
-};
-
-//-------------------------------------------------------------------------------------
-// ***** LatencyTestCalibrate
-// LatencyTestCalibrate specifies colors used for Latency Tester calibration.
-struct LatencyTestCalibrate
-{
- LatencyTestCalibrate(const Color& value)
- : Value(value)
- {
- }
-
- // The color being calibrated to.
- Color Value;
-};
-
-//-------------------------------------------------------------------------------------
-// ***** LatencyTestStartTest
-// LatencyTestStartTest specifies values used when starting the Latency Tester test.
-struct LatencyTestStartTest
-{
- LatencyTestStartTest(const Color& targetValue)
- : TargetValue(targetValue)
- {
- }
-
- // The color value that the display is being set to.
- Color TargetValue;
-};
-
-//-------------------------------------------------------------------------------------
-// ***** LatencyTestDisplay
-// LatencyTestDisplay sets the mode and contents of the Latency Tester LED display.
-// See the 'Latency Tester Specification' document for more details.
-struct LatencyTestDisplay
-{
- LatencyTestDisplay(UByte mode, UInt32 value)
- : Mode(mode), Value(value)
- {
- }
-
- UByte Mode; // The display mode that we wish to select.
- UInt32 Value; // The value to display.
-};
-
-//-------------------------------------------------------------------------------------
-// ***** LatencyTestDevice
-
-// LatencyTestDevice provides an interface to the Oculus Latency Tester which is used to test 'motion to photon' latency.
-class LatencyTestDevice : public HIDDeviceBase, public DeviceBase
-{
-public:
- LatencyTestDevice()
- { }
-
- // Static constant for this device type, used in template cast type checks.
- enum { EnumDeviceType = Device_LatencyTester };
-
- virtual DeviceType GetType() const { return Device_LatencyTester; }
-
- // Specifies configuration information including the threshold for triggering a detected color change,
- // and a flag to enable a stream of sensor values (typically used for debugging).
- virtual bool SetConfiguration(const LatencyTestConfiguration& configuration, bool waitFlag = false) = 0;
-
- // Get configuration information from device.
- virtual bool GetConfiguration(LatencyTestConfiguration* configuration) = 0;
-
- // Used to calibrate the latency tester at the start of a test. Calibration information is lost
- // when power is removed from the device.
- virtual bool SetCalibrate(const LatencyTestCalibrate& calibrate, bool waitFlag = false) = 0;
-
- // Get calibration information from device.
- virtual bool GetCalibrate(LatencyTestCalibrate* calibrate) = 0;
-
- // Triggers the start of a measurement. This starts the millisecond timer on the device and
- // causes it to respond with the 'MessageLatencyTestStarted' message.
- virtual bool SetStartTest(const LatencyTestStartTest& start, bool waitFlag = false) = 0;
-
- // Used to set the value displayed on the LED display panel.
- virtual bool SetDisplay(const LatencyTestDisplay& display, bool waitFlag = false) = 0;
-
- virtual DeviceBase* GetDevice() { return this; }
-};
-
-} // namespace OVR
-
-#endif
+/************************************************************************************
+
+PublicHeader: OVR.h
+Filename : OVR_Device.h
+Content : Definition of HMD-related Device interfaces
+Created : September 21, 2012
+Authors : Michael Antonov
+
+Copyright : Copyright 2012 Oculus VR, Inc. All Rights reserved.
+
+Use of this software is subject to the terms of the Oculus license
+agreement provided at the time of installation or download, or which
+otherwise accompanies this software in either electronic or hard copy form.
+
+*************************************************************************************/
+
+#ifndef OVR_Device_h
+#define OVR_Device_h
+
+#include "OVR_DeviceConstants.h"
+#include "OVR_DeviceHandle.h"
+#include "OVR_DeviceMessages.h"
+#include "OVR_HIDDeviceBase.h"
+
+#include "Kernel/OVR_Atomic.h"
+#include "Kernel/OVR_RefCount.h"
+#include "Kernel/OVR_String.h"
+
+namespace OVR {
+
+// Declared externally
+class Profile;
+class ProfileManager; // << Should be renamed for consistency
+
+// Forward declarations
+class SensorDevice;
+class DeviceCommon;
+class DeviceManager;
+
+// MessageHandler is a base class from which users derive to receive messages,
+// its OnMessage handler will be called for messages once it is installed on
+// a device. Same message handler can be installed on multiple devices.
+class MessageHandler
+{
+ friend class MessageHandlerImpl;
+public:
+ MessageHandler();
+ virtual ~MessageHandler();
+
+ // Returns 'true' if handler is currently installed on any devices.
+ bool IsHandlerInstalled() const;
+
+ // Should be called from derived class destructor to avoid handler
+ // being called after it exits.
+ void RemoveHandlerFromDevices();
+
+ // Returns a pointer to the internal lock object that is locked by a
+ // background thread while OnMessage() is called.
+ // This lock guaranteed to survive until ~MessageHandler.
+ Lock* GetHandlerLock() const;
+
+
+ virtual void OnMessage(const Message&) { }
+
+ // Determines if handler supports a specific message type. Can
+ // be used to filter out entire message groups. The result
+ // returned by this function shouldn't change after handler creation.
+ virtual bool SupportsMessageType(MessageType) const { return true; }
+
+private:
+ UPInt Internal[4];
+};
+
+
+//-------------------------------------------------------------------------------------
+// ***** DeviceBase
+
+// DeviceBase is the base class for all OVR Devices. It provides the following basic
+// functionality:
+// - Reports device type, manager, and associated parent (if any).
+// - Supports installable message handlers, which are notified of device events.
+// - Device objects are created through DeviceHandle::CreateDevice or more commonly
+// through DeviceEnumerator<>::CreateDevice.
+// - Created devices are reference counted, starting with RefCount of 1.
+// - Device is resources are cleaned up when it is Released, although its handles
+// may survive longer if referenced.
+
+class DeviceBase : public NewOverrideBase
+{
+ friend class DeviceHandle;
+ friend class DeviceManagerImpl;
+public:
+
+ // Enumerating DeviceBase enumerates all devices.
+ enum { EnumDeviceType = Device_All };
+
+ virtual ~DeviceBase() { }
+ virtual void AddRef();
+ virtual void Release();
+
+ virtual DeviceBase* GetParent() const;
+ virtual DeviceManager* GetManager() const;
+
+ virtual void SetMessageHandler(MessageHandler* handler);
+ virtual MessageHandler* GetMessageHandler() const;
+
+ virtual DeviceType GetType() const;
+ virtual bool GetDeviceInfo(DeviceInfo* info) const;
+
+ // returns the MessageHandler's lock
+ Lock* GetHandlerLock() const;
+protected:
+ // Internal
+ virtual DeviceCommon* getDeviceCommon() const = 0;
+};
+
+
+//-------------------------------------------------------------------------------------
+// ***** DeviceInfo
+
+// DeviceInfo describes a device and its capabilities, obtained by calling
+// GetDeviceInfo. This base class only contains device-independent functionality;
+// users will normally use a derived HMDInfo or SensorInfo classes for more
+// extensive device info.
+
+class DeviceInfo
+{
+public:
+ DeviceInfo() : InfoClassType(Device_None), Type(Device_None), Version(0)
+ { ProductName[0] = Manufacturer[0] = 0; }
+
+ enum { MaxNameLength = 32 };
+
+ // Type of device for which DeviceInfo is intended.
+ // This will be set to Device_HMD for HMDInfo structure, note that this may be
+ // different form the actual device type since (Device_None) is valid.
+ const DeviceType InfoClassType;
+ // Type of device this describes. This must be the same as InfoClassType when
+ // InfoClassType != Device_None.
+ DeviceType Type;
+ // Name string describing the product: "Oculus Rift DK1", etc.
+ char ProductName[MaxNameLength];
+ char Manufacturer[MaxNameLength];
+ unsigned Version;
+
+protected:
+ DeviceInfo(DeviceType type) : InfoClassType(type), Type(type), Version(0)
+ { ProductName[0] = Manufacturer[0] = 0; }
+ void operator = (const DeviceInfo&) { OVR_ASSERT(0); } // Assignment not allowed.
+};
+
+
+//-------------------------------------------------------------------------------------
+// DeviceEnumerationArgs provides device enumeration argumenrs for DeviceManager::EnumerateDevicesEx.
+class DeviceEnumerationArgs
+{
+public:
+ DeviceEnumerationArgs(DeviceType enumType, bool availableOnly)
+ : EnumType(enumType), AvailableOnly(availableOnly)
+ { }
+
+ // Helper; returns true if args match our enumeration criteria.
+ bool MatchRule(DeviceType type, bool available) const
+ {
+ return ((EnumType == type) || (EnumType == Device_All)) &&
+ (available || !AvailableOnly);
+ }
+
+protected:
+ DeviceType EnumType;
+ bool AvailableOnly;
+};
+
+
+// DeviceEnumerator<> is used to enumerate and create devices of specified class,
+// it is returned by calling MeviceManager::EnumerateDevices. Initially, the enumerator will
+// refer to the first device of specified type. Additional devices can be accessed by
+// calling Next().
+
+template<class T = DeviceBase>
+class DeviceEnumerator : public DeviceHandle
+{
+ friend class DeviceManager;
+ friend class DeviceManagerImpl;
+public:
+ DeviceEnumerator()
+ : DeviceHandle(), EnumArgs(Device_None, true) { }
+
+ // Next advances enumeration to the next device that first criteria.
+ // Returns false if no more devices exist that match enumeration criteria.
+ bool Next() { return enumerateNext(EnumArgs); }
+
+ // Creates an instance of the device referenced by enumerator; returns null
+ // if enumerator does not refer to a valid device or device is unavailable.
+ // If device was already created, the same object with incremented ref-count is returned.
+ T* CreateDevice() { return static_cast<T*>(DeviceHandle::CreateDevice()); }
+
+protected:
+ DeviceEnumerator(const DeviceHandle &dev, const DeviceEnumerationArgs& args)
+ : DeviceHandle(dev), EnumArgs(args)
+ { }
+
+ DeviceEnumerationArgs EnumArgs;
+};
+
+//-------------------------------------------------------------------------------------
+// ***** DeviceManager
+
+// DeviceManager maintains and provides access to devices supported by OVR, such as
+// HMDs and sensors. A single instance of DeviceManager is normally created at
+// program startup, allowing devices to be enumerated and created. DeviceManager is
+// reference counted and is AddRefed by its created child devices, causing it to
+// always be the last object that is released.
+//
+// Install MessageHandler on DeviceManager to detect when devices are inserted or removed.
+//
+// The following code will create the manager and its first available HMDDevice,
+// and then release it when not needed:
+//
+// DeviceManager* manager = DeviceManager::Create();
+// HMDDevice* hmd = manager->EnumerateDevices<HMDDevice>().CreateDevice();
+//
+// if (hmd) hmd->Release();
+// if (manager) manager->Release();
+
+
+class DeviceManager : public DeviceBase
+{
+public:
+
+ DeviceManager()
+ { }
+
+ // DeviceBase implementation.
+ virtual DeviceType GetType() const { return Device_Manager; }
+ virtual DeviceManager* GetManager() const { return const_cast<DeviceManager*>(this); }
+
+ // Every DeviceManager has an associated profile manager, which us used to store
+ // user settings that may affect device behavior.
+ virtual ProfileManager* GetProfileManager() const = 0;
+
+
+ // EnumerateDevices enumerates all of the available devices of the specified class,
+ // returning an enumerator that references the first device. An empty enumerator is
+ // returned if no devices are available. The following APIs are exposed through
+ // DeviceEnumerator:
+ // DeviceEnumerator::GetType() - Check device type. Returns Device_None
+ // if no device was found/pointed to.
+ // DeviceEnumerator::GetDeviceInfo() - Get more information on device.
+ // DeviceEnumerator::CreateDevice() - Create an instance of device.
+ // DeviceEnumerator::Next() - Move onto next device.
+ template<class D>
+ DeviceEnumerator<D> EnumerateDevices(bool availableOnly = true)
+ {
+ // TBD: A cleaner (but less efficient) alternative is though enumeratorFromHandle.
+ DeviceEnumerator<> e = EnumerateDevicesEx(DeviceEnumerationArgs((DeviceType)D::EnumDeviceType, availableOnly));
+ return *reinterpret_cast<DeviceEnumerator<D>*>(&e);
+ }
+
+ // EnumerateDevicesEx provides internal implementation for device enumeration, enumerating
+ // devices based on dynamically specified DeviceType in DeviceEnumerationArgs.
+ // End users should call DeumerateDevices<>() instead.
+ virtual DeviceEnumerator<> EnumerateDevicesEx(const DeviceEnumerationArgs& args) = 0;
+
+ // Creates a new DeviceManager. Only one instance of DeviceManager should be created at a time.
+ static DeviceManager* Create();
+
+ // Static constant for this device type, used in template cast type checks.
+ enum { EnumDeviceType = Device_Manager };
+
+
+
+ // Adds a device (DeviceCreateDesc*) into Devices. Returns NULL,
+ // if unsuccessful or device is already in the list.
+ virtual Ptr<DeviceCreateDesc> AddDevice_NeedsLock(const DeviceCreateDesc& createDesc) = 0;
+
+protected:
+ DeviceEnumerator<> enumeratorFromHandle(const DeviceHandle& h, const DeviceEnumerationArgs& args)
+ { return DeviceEnumerator<>(h, args); }
+
+ DeviceManager* getThis() { return this; }
+};
+
+
+
+//-------------------------------------------------------------------------------------
+// ***** HMDInfo
+
+// This structure describes various aspects of the HMD allowing us to configure rendering.
+//
+// Currently included data:
+// - Physical screen dimensions, resolution, and eye distances.
+// (some of these will be configurable with a tool in the future).
+// These arguments allow us to properly setup projection across HMDs.
+// - DisplayDeviceName for identifying HMD screen; system-specific interpretation.
+//
+// TBD:
+// - Power on/ off?
+// - Sensor rates and capabilities
+// - Distortion radius/variables
+// - Screen update frequency
+// - Distortion needed flag
+// - Update modes:
+// Set update mode: Stereo (both sides together), mono (same in both eyes),
+// Alternating, Alternating scan-lines.
+
+class HMDInfo : public DeviceInfo
+{
+public:
+ // Size of the entire screen, in pixels.
+ unsigned HResolution, VResolution;
+ // Physical dimensions of the active screen in meters. Can be used to calculate
+ // projection center while considering IPD.
+ float HScreenSize, VScreenSize;
+ // Physical offset from the top of the screen to the eye center, in meters.
+ // This will usually, but not necessarily be half of VScreenSize.
+ float VScreenCenter;
+ // Distance from the eye to screen surface, in meters.
+ // Useful for calculating FOV and projection.
+ float EyeToScreenDistance;
+ // Distance between physical lens centers useful for calculating distortion center.
+ float LensSeparationDistance;
+ // Configured distance between the user's eye centers, in meters. Defaults to 0.064.
+ float InterpupillaryDistance;
+
+ // Radial distortion correction coefficients.
+ // The distortion assumes that the input texture coordinates will be scaled
+ // by the following equation:
+ // uvResult = uvInput * (K0 + K1 * uvLength^2 + K2 * uvLength^4)
+ // Where uvInput is the UV vector from the center of distortion in direction
+ // of the mapped pixel, uvLength is the magnitude of that vector, and uvResult
+ // the corresponding location after distortion.
+ float DistortionK[4];
+
+ float ChromaAbCorrection[4];
+
+ // Desktop coordinate position of the screen (can be negative; may not be present on all platforms)
+ int DesktopX, DesktopY;
+
+ // Windows:
+ // "\\\\.\\DISPLAY3", etc. Can be used in EnumDisplaySettings/CreateDC.
+ char DisplayDeviceName[32];
+
+ // MacOS:
+ long DisplayId;
+
+
+ HMDInfo()
+ : DeviceInfo(Device_HMD),
+ HResolution(0), VResolution(0), HScreenSize(0), VScreenSize(0),
+ VScreenCenter(0), EyeToScreenDistance(0),
+ LensSeparationDistance(0), InterpupillaryDistance(0),
+ DesktopX(0), DesktopY(0), DisplayId(0)
+ {
+ DisplayDeviceName[0] = 0;
+ memset(DistortionK, 0, sizeof(DistortionK));
+ DistortionK[0] = 1;
+ ChromaAbCorrection[0] = ChromaAbCorrection[2] = 1;
+ ChromaAbCorrection[1] = ChromaAbCorrection[3] = 0;
+ }
+
+ // Operator = copies local fields only (base class must be correct already)
+ void operator = (const HMDInfo& src)
+ {
+ HResolution = src.HResolution;
+ VResolution = src.VResolution;
+ HScreenSize = src.HScreenSize;
+ VScreenSize = src.VScreenSize;
+ VScreenCenter = src.VScreenCenter;
+ EyeToScreenDistance = src.EyeToScreenDistance;
+ LensSeparationDistance = src.LensSeparationDistance;
+ InterpupillaryDistance = src.InterpupillaryDistance;
+ DistortionK[0] = src.DistortionK[0];
+ DistortionK[1] = src.DistortionK[1];
+ DistortionK[2] = src.DistortionK[2];
+ DistortionK[3] = src.DistortionK[3];
+ ChromaAbCorrection[0] = src.ChromaAbCorrection[0];
+ ChromaAbCorrection[1] = src.ChromaAbCorrection[1];
+ ChromaAbCorrection[2] = src.ChromaAbCorrection[2];
+ ChromaAbCorrection[3] = src.ChromaAbCorrection[3];
+ DesktopX = src.DesktopX;
+ DesktopY = src.DesktopY;
+ memcpy(DisplayDeviceName, src.DisplayDeviceName, sizeof(DisplayDeviceName));
+ DisplayId = src.DisplayId;
+ }
+
+ bool IsSameDisplay(const HMDInfo& o) const
+ {
+ return DisplayId == o.DisplayId &&
+ String::CompareNoCase(DisplayDeviceName,
+ o.DisplayDeviceName) == 0;
+ }
+
+};
+
+
+// HMDDevice represents an Oculus HMD device unit. An instance of this class
+// is typically created from the DeviceManager.
+// After HMD device is created, we its sensor data can be obtained by
+// first creating a Sensor object and then.
+
+// TBD:
+// - Configure Sensor
+// - APIs to set On-Screen message, other states?
+
+class HMDDevice : public DeviceBase
+{
+public:
+ HMDDevice()
+ { }
+
+ // Static constant for this device type, used in template cast type checks.
+ enum { EnumDeviceType = Device_HMD };
+
+ virtual DeviceType GetType() const { return Device_HMD; }
+
+ // Creates a sensor associated with this HMD.
+ virtual SensorDevice* GetSensor() = 0;
+
+
+ // Requests the currently used profile. This profile affects the
+ // settings reported by HMDInfo.
+ virtual Profile* GetProfile() const = 0;
+ // Obtains the currently used profile name. This is initialized to the default
+ // profile name, if any; it can then be changed per-device by SetProfileName.
+ virtual const char* GetProfileName() const = 0;
+ // Sets the profile user name, changing the data returned by GetProfileInfo.
+ virtual bool SetProfileName(const char* name) = 0;
+
+
+ // Disconnects from real HMD device. This HMDDevice remains as 'fake' HMD.
+ // SensorDevice ptr is used to restore the 'fake' HMD (can be NULL).
+ HMDDevice* Disconnect(SensorDevice*);
+
+ // Returns 'true' if HMD device is a 'fake' HMD (was created this way or
+ // 'Disconnect' method was called).
+ bool IsDisconnected() const;
+};
+
+
+//-------------------------------------------------------------------------------------
+// ***** SensorRange & SensorInfo
+
+// SensorRange specifies maximum value ranges that SensorDevice hardware is configured
+// to detect. Although this range doesn't affect the scale of MessageBodyFrame values,
+// physical motions whose positive or negative magnitude is outside the specified range
+// may get clamped or misreported. Setting lower values may result in higher precision
+// tracking.
+struct SensorRange
+{
+ SensorRange(float maxAcceleration = 0.0f, float maxRotationRate = 0.0f,
+ float maxMagneticField = 0.0f)
+ : MaxAcceleration(maxAcceleration), MaxRotationRate(maxRotationRate),
+ MaxMagneticField(maxMagneticField)
+ { }
+
+ // Maximum detected acceleration in m/s^2. Up to 8*G equivalent support guaranteed,
+ // where G is ~9.81 m/s^2.
+ // Oculus DK1 HW has thresholds near: 2, 4 (default), 8, 16 G.
+ float MaxAcceleration;
+ // Maximum detected angular velocity in rad/s. Up to 8*Pi support guaranteed.
+ // Oculus DK1 HW thresholds near: 1, 2, 4, 8 Pi (default).
+ float MaxRotationRate;
+ // Maximum detectable Magnetic field strength in Gauss. Up to 2.5 Gauss support guaranteed.
+ // Oculus DK1 HW thresholds near: 0.88, 1.3, 1.9, 2.5 gauss.
+ float MaxMagneticField;
+};
+
+// SensorInfo describes capabilities of the sensor device.
+class SensorInfo : public DeviceInfo
+{
+public:
+ SensorInfo() : DeviceInfo(Device_Sensor), VendorId(0), ProductId(0)
+ {
+ SerialNumber[0] = 0;
+ }
+
+ // HID Vendor and ProductId of the device.
+ UInt16 VendorId;
+ UInt16 ProductId;
+ // MaxRanges report maximum sensor range values supported by HW.
+ SensorRange MaxRanges;
+ // Sensor (and display) serial number.
+ char SerialNumber[20];
+
+private:
+ void operator = (const SensorInfo&) { OVR_ASSERT(0); } // Assignment not allowed.
+};
+
+
+//-------------------------------------------------------------------------------------
+// ***** SensorDevice
+
+// SensorDevice is an interface to sensor data.
+// Install a MessageHandler of SensorDevice instance to receive MessageBodyFrame
+// notifications.
+//
+// TBD: Add Polling API? More HID interfaces?
+
+class SensorDevice : public HIDDeviceBase, public DeviceBase
+{
+public:
+ SensorDevice()
+ { }
+
+ // Static constant for this device type, used in template cast type checks.
+ enum { EnumDeviceType = Device_Sensor };
+
+ virtual DeviceType GetType() const { return Device_Sensor; }
+
+
+ // CoordinateFrame defines whether messages come in the coordinate frame
+ // of the sensor device or HMD, which has a different internal sensor.
+ // Sensors obtained form the HMD will automatically use HMD coordinates.
+ enum CoordinateFrame
+ {
+ Coord_Sensor = 0,
+ Coord_HMD = 1
+ };
+
+ virtual void SetCoordinateFrame(CoordinateFrame coordframe) = 0;
+ virtual CoordinateFrame GetCoordinateFrame() const = 0;
+
+ // Sets report rate (in Hz) of MessageBodyFrame messages (delivered through MessageHandler::OnMessage call).
+ // Currently supported maximum rate is 1000Hz. If the rate is set to 500 or 333 Hz then OnMessage will be
+ // called twice or thrice at the same 'tick'.
+ // If the rate is < 333 then the OnMessage / MessageBodyFrame will be called three
+ // times for each 'tick': the first call will contain averaged values, the second
+ // and third calls will provide with most recent two recorded samples.
+ virtual void SetReportRate(unsigned rateHz) = 0;
+ // Returns currently set report rate, in Hz. If 0 - error occurred.
+ // Note, this value may be different from the one provided for SetReportRate. The return
+ // value will contain the actual rate.
+ virtual unsigned GetReportRate() const = 0;
+
+ // Sets maximum range settings for the sensor described by SensorRange.
+ // The function will fail if you try to pass values outside Maximum supported
+ // by the HW, as described by SensorInfo.
+ // Pass waitFlag == true to wait for command completion. For waitFlag == true,
+ // returns true if the range was applied successfully (no HW error).
+ // For waitFlag = false, return 'true' means that command was enqueued successfully.
+ virtual bool SetRange(const SensorRange& range, bool waitFlag = false) = 0;
+
+ // Return the current sensor range settings for the device. These may not exactly
+ // match the values applied through SetRange.
+ virtual void GetRange(SensorRange* range) const = 0;
+};
+
+//-------------------------------------------------------------------------------------
+// ***** LatencyTestConfiguration
+// LatencyTestConfiguration specifies configuration information for the Oculus Latency Tester device.
+struct LatencyTestConfiguration
+{
+ LatencyTestConfiguration(const Color& threshold, bool sendSamples = false)
+ : Threshold(threshold), SendSamples(sendSamples)
+ {
+ }
+
+ // The color threshold for triggering a detected display change.
+ Color Threshold;
+ // Flag specifying whether we wish to receive a stream of color values from the sensor.
+ bool SendSamples;
+};
+
+//-------------------------------------------------------------------------------------
+// ***** LatencyTestDisplay
+// LatencyTestDisplay sets the mode and contents of the Latency Tester LED display.
+// See the 'Latency Tester Specification' document for more details.
+struct LatencyTestDisplay
+{
+ LatencyTestDisplay(UByte mode, UInt32 value)
+ : Mode(mode), Value(value)
+ {
+ }
+
+ UByte Mode; // The display mode that we wish to select.
+ UInt32 Value; // The value to display.
+};
+
+//-------------------------------------------------------------------------------------
+// ***** LatencyTestDevice
+
+// LatencyTestDevice provides an interface to the Oculus Latency Tester which is used to test 'motion to photon' latency.
+class LatencyTestDevice : public HIDDeviceBase, public DeviceBase
+{
+public:
+ LatencyTestDevice()
+ { }
+
+ // Static constant for this device type, used in template cast type checks.
+ enum { EnumDeviceType = Device_LatencyTester };
+
+ virtual DeviceType GetType() const { return Device_LatencyTester; }
+
+ // Specifies configuration information including the threshold for triggering a detected color change,
+ // and a flag to enable a stream of sensor values (typically used for debugging).
+ virtual bool SetConfiguration(const LatencyTestConfiguration& configuration, bool waitFlag = false) = 0;
+
+ // Get configuration information from device.
+ virtual bool GetConfiguration(LatencyTestConfiguration* configuration) = 0;
+
+ // Used to calibrate the latency tester at the start of a test. Display the specified color on the screen
+ // beneath the latency tester and then call this method. Calibration information is lost
+ // when power is removed from the device.
+ virtual bool SetCalibrate(const Color& calibrationColor, bool waitFlag = false) = 0;
+
+ // Triggers the start of a measurement. This starts the millisecond timer on the device and
+ // causes it to respond with the 'MessageLatencyTestStarted' message.
+ virtual bool SetStartTest(const Color& targetColor, bool waitFlag = false) = 0;
+
+ // Used to set the value displayed on the LED display panel.
+ virtual bool SetDisplay(const LatencyTestDisplay& display, bool waitFlag = false) = 0;
+
+ virtual DeviceBase* GetDevice() { return this; }
+};
+
+} // namespace OVR
+
+#endif
diff --git a/LibOVR/Src/OVR_DeviceConstants.h b/LibOVR/Src/OVR_DeviceConstants.h
index b729d5f..41342ce 100644
--- a/LibOVR/Src/OVR_DeviceConstants.h
+++ b/LibOVR/Src/OVR_DeviceConstants.h
@@ -1,38 +1,38 @@
-/************************************************************************************
-
-PublicHeader: OVR.h
-Filename : OVR_DeviceConstants.h
-Content : Device constants
-Created : February 5, 2013
-Authors : Lee Cooper
-
-Copyright : Copyright 2013 Oculus VR, Inc. All Rights reserved.
-
-Use of this software is subject to the terms of the Oculus license
-agreement provided at the time of installation or download, or which
-otherwise accompanies this software in either electronic or hard copy form.
-
-*************************************************************************************/
-
-#ifndef OVR_DeviceConstants_h
-#define OVR_DeviceConstants_h
-
-namespace OVR {
-
-
-//-------------------------------------------------------------------------------------
-// Different device types supported by OVR; this type is reported by DeviceBase::GetType.
-//
-enum DeviceType
-{
- Device_None = 0,
- Device_Manager = 1,
- Device_HMD = 2,
- Device_Sensor = 3,
- Device_LatencyTester = 4,
- Device_All = 0xFF // Set for enumeration only, to enumerate all device types.
-};
-
-} // namespace OVR
-
-#endif
+/************************************************************************************
+
+PublicHeader: OVR.h
+Filename : OVR_DeviceConstants.h
+Content : Device constants
+Created : February 5, 2013
+Authors : Lee Cooper
+
+Copyright : Copyright 2013 Oculus VR, Inc. All Rights reserved.
+
+Use of this software is subject to the terms of the Oculus license
+agreement provided at the time of installation or download, or which
+otherwise accompanies this software in either electronic or hard copy form.
+
+*************************************************************************************/
+
+#ifndef OVR_DeviceConstants_h
+#define OVR_DeviceConstants_h
+
+namespace OVR {
+
+
+//-------------------------------------------------------------------------------------
+// Different device types supported by OVR; this type is reported by DeviceBase::GetType.
+//
+enum DeviceType
+{
+ Device_None = 0,
+ Device_Manager = 1,
+ Device_HMD = 2,
+ Device_Sensor = 3,
+ Device_LatencyTester = 4,
+ Device_All = 0xFF // Set for enumeration only, to enumerate all device types.
+};
+
+} // namespace OVR
+
+#endif
diff --git a/LibOVR/Src/OVR_DeviceHandle.cpp b/LibOVR/Src/OVR_DeviceHandle.cpp
index 5a0fce6..d1e831e 100644
--- a/LibOVR/Src/OVR_DeviceHandle.cpp
+++ b/LibOVR/Src/OVR_DeviceHandle.cpp
@@ -1,174 +1,174 @@
-/************************************************************************************
-
-Filename : OVR_DeviceHandle.cpp
-Content : Implementation of device handle class
-Created : February 5, 2013
-Authors : Lee Cooper
-
-Copyright : Copyright 2013 Oculus VR, Inc. All Rights reserved.
-
-Use of this software is subject to the terms of the Oculus license
-agreement provided at the time of installation or download, or which
-otherwise accompanies this software in either electronic or hard copy form.
-
-*************************************************************************************/
-
-#include "OVR_DeviceHandle.h"
-
-#include "OVR_DeviceImpl.h"
-
-namespace OVR {
-
-//-------------------------------------------------------------------------------------
-// ***** DeviceHandle
-
-DeviceHandle::DeviceHandle(DeviceCreateDesc* impl) : pImpl(impl)
-{
- if (pImpl)
- pImpl->AddRef();
-}
-
-DeviceHandle::DeviceHandle(const DeviceHandle& src) : pImpl(src.pImpl)
-{
- if (pImpl)
- pImpl->AddRef();
-}
-
-DeviceHandle::~DeviceHandle()
-{
- if (pImpl)
- pImpl->Release();
-}
-
-void DeviceHandle::operator = (const DeviceHandle& src)
-{
- if (src.pImpl)
- src.pImpl->AddRef();
- if (pImpl)
- pImpl->Release();
- pImpl = src.pImpl;
-}
-
-DeviceBase* DeviceHandle::GetDevice_AddRef() const
-{
- if (pImpl && pImpl->pDevice)
- {
- pImpl->pDevice->AddRef();
- return pImpl->pDevice;
- }
- return NULL;
-}
-
-// Returns true, if the handle contains the same device ptr
-// as specified in the parameter.
-bool DeviceHandle::IsDevice(DeviceBase* pdev) const
-{
- return (pdev && pImpl && pImpl->pDevice) ?
- pImpl->pDevice == pdev : false;
-}
-
-DeviceType DeviceHandle::GetType() const
-{
- return pImpl ? pImpl->Type : Device_None;
-}
-
-bool DeviceHandle::GetDeviceInfo(DeviceInfo* info) const
-{
- return pImpl ? pImpl->GetDeviceInfo(info) : false;
-}
-bool DeviceHandle::IsAvailable() const
-{
- // This isn't "atomically safe", but the function only returns the
- // recent state that may change.
- return pImpl ? (pImpl->Enumerated && pImpl->pLock->pManager) : false;
-}
-
-bool DeviceHandle::IsCreated() const
-{
- return pImpl ? (pImpl->pDevice != 0) : false;
-}
-
-DeviceBase* DeviceHandle::CreateDevice()
-{
- if (!pImpl)
- return 0;
-
- DeviceBase* device = 0;
- Ptr<DeviceManagerImpl> manager= 0;
-
- // Since both manager and device pointers can only be destroyed during a lock,
- // hold it while checking for availability.
- // AddRef to manager so that it doesn't get released on us.
- {
- Lock::Locker deviceLockScope(pImpl->GetLock());
-
- if (pImpl->pDevice)
- {
- pImpl->pDevice->AddRef();
- return pImpl->pDevice;
- }
- manager = pImpl->GetManagerImpl();
- }
-
- if (manager)
- {
- if (manager->GetThreadId() != OVR::GetCurrentThreadId())
- {
- // Queue up a CreateDevice request. This fills in '&device' with AddRefed value,
- // or keep it at null.
- manager->GetThreadQueue()->PushCallAndWaitResult(
- manager.GetPtr(), &DeviceManagerImpl::CreateDevice_MgrThread,
- &device, pImpl, (DeviceBase*)0);
- }
- else
- device = manager->CreateDevice_MgrThread(pImpl, (DeviceBase*)0);
- }
- return device;
-}
-
-void DeviceHandle::Clear()
-{
- if (pImpl)
- {
- pImpl->Release();
- pImpl = 0;
- }
-}
-
-bool DeviceHandle::enumerateNext(const DeviceEnumerationArgs& args)
-{
- if (GetType() == Device_None)
- return false;
-
- Ptr<DeviceManagerImpl> managerKeepAlive;
- Lock::Locker lockScope(pImpl->GetLock());
-
- DeviceCreateDesc* next = pImpl;
- // If manager was destroyed, we get removed from the list.
- if (!pImpl->pNext)
- return false;
-
- managerKeepAlive = next->GetManagerImpl();
- OVR_ASSERT(managerKeepAlive);
-
- do {
- next = next->pNext;
-
- if (managerKeepAlive->Devices.IsNull(next))
- {
- pImpl->Release();
- pImpl = 0;
- return false;
- }
-
- } while(!args.MatchRule(next->Type, next->Enumerated));
-
- next->AddRef();
- pImpl->Release();
- pImpl = next;
-
- return true;
-}
-
-} // namespace OVR
-
+/************************************************************************************
+
+Filename : OVR_DeviceHandle.cpp
+Content : Implementation of device handle class
+Created : February 5, 2013
+Authors : Lee Cooper
+
+Copyright : Copyright 2013 Oculus VR, Inc. All Rights reserved.
+
+Use of this software is subject to the terms of the Oculus license
+agreement provided at the time of installation or download, or which
+otherwise accompanies this software in either electronic or hard copy form.
+
+*************************************************************************************/
+
+#include "OVR_DeviceHandle.h"
+
+#include "OVR_DeviceImpl.h"
+
+namespace OVR {
+
+//-------------------------------------------------------------------------------------
+// ***** DeviceHandle
+
+DeviceHandle::DeviceHandle(DeviceCreateDesc* impl) : pImpl(impl)
+{
+ if (pImpl)
+ pImpl->AddRef();
+}
+
+DeviceHandle::DeviceHandle(const DeviceHandle& src) : pImpl(src.pImpl)
+{
+ if (pImpl)
+ pImpl->AddRef();
+}
+
+DeviceHandle::~DeviceHandle()
+{
+ if (pImpl)
+ pImpl->Release();
+}
+
+void DeviceHandle::operator = (const DeviceHandle& src)
+{
+ if (src.pImpl)
+ src.pImpl->AddRef();
+ if (pImpl)
+ pImpl->Release();
+ pImpl = src.pImpl;
+}
+
+DeviceBase* DeviceHandle::GetDevice_AddRef() const
+{
+ if (pImpl && pImpl->pDevice)
+ {
+ pImpl->pDevice->AddRef();
+ return pImpl->pDevice;
+ }
+ return NULL;
+}
+
+// Returns true, if the handle contains the same device ptr
+// as specified in the parameter.
+bool DeviceHandle::IsDevice(DeviceBase* pdev) const
+{
+ return (pdev && pImpl && pImpl->pDevice) ?
+ pImpl->pDevice == pdev : false;
+}
+
+DeviceType DeviceHandle::GetType() const
+{
+ return pImpl ? pImpl->Type : Device_None;
+}
+
+bool DeviceHandle::GetDeviceInfo(DeviceInfo* info) const
+{
+ return pImpl ? pImpl->GetDeviceInfo(info) : false;
+}
+bool DeviceHandle::IsAvailable() const
+{
+ // This isn't "atomically safe", but the function only returns the
+ // recent state that may change.
+ return pImpl ? (pImpl->Enumerated && pImpl->pLock->pManager) : false;
+}
+
+bool DeviceHandle::IsCreated() const
+{
+ return pImpl ? (pImpl->pDevice != 0) : false;
+}
+
+DeviceBase* DeviceHandle::CreateDevice()
+{
+ if (!pImpl)
+ return 0;
+
+ DeviceBase* device = 0;
+ Ptr<DeviceManagerImpl> manager= 0;
+
+ // Since both manager and device pointers can only be destroyed during a lock,
+ // hold it while checking for availability.
+ // AddRef to manager so that it doesn't get released on us.
+ {
+ Lock::Locker deviceLockScope(pImpl->GetLock());
+
+ if (pImpl->pDevice)
+ {
+ pImpl->pDevice->AddRef();
+ return pImpl->pDevice;
+ }
+ manager = pImpl->GetManagerImpl();
+ }
+
+ if (manager)
+ {
+ if (manager->GetThreadId() != OVR::GetCurrentThreadId())
+ {
+ // Queue up a CreateDevice request. This fills in '&device' with AddRefed value,
+ // or keep it at null.
+ manager->GetThreadQueue()->PushCallAndWaitResult(
+ manager.GetPtr(), &DeviceManagerImpl::CreateDevice_MgrThread,
+ &device, pImpl, (DeviceBase*)0);
+ }
+ else
+ device = manager->CreateDevice_MgrThread(pImpl, (DeviceBase*)0);
+ }
+ return device;
+}
+
+void DeviceHandle::Clear()
+{
+ if (pImpl)
+ {
+ pImpl->Release();
+ pImpl = 0;
+ }
+}
+
+bool DeviceHandle::enumerateNext(const DeviceEnumerationArgs& args)
+{
+ if (GetType() == Device_None)
+ return false;
+
+ Ptr<DeviceManagerImpl> managerKeepAlive;
+ Lock::Locker lockScope(pImpl->GetLock());
+
+ DeviceCreateDesc* next = pImpl;
+ // If manager was destroyed, we get removed from the list.
+ if (!pImpl->pNext)
+ return false;
+
+ managerKeepAlive = next->GetManagerImpl();
+ OVR_ASSERT(managerKeepAlive);
+
+ do {
+ next = next->pNext;
+
+ if (managerKeepAlive->Devices.IsNull(next))
+ {
+ pImpl->Release();
+ pImpl = 0;
+ return false;
+ }
+
+ } while(!args.MatchRule(next->Type, next->Enumerated));
+
+ next->AddRef();
+ pImpl->Release();
+ pImpl = next;
+
+ return true;
+}
+
+} // namespace OVR
+
diff --git a/LibOVR/Src/OVR_DeviceHandle.h b/LibOVR/Src/OVR_DeviceHandle.h
index 4ac4387..dc8b267 100644
--- a/LibOVR/Src/OVR_DeviceHandle.h
+++ b/LibOVR/Src/OVR_DeviceHandle.h
@@ -1,97 +1,97 @@
-/************************************************************************************
-
-PublicHeader: OVR.h
-Filename : OVR_DeviceHandle.h
-Content : Handle to a device that was enumerated
-Created : February 5, 2013
-Authors : Lee Cooper
-
-Copyright : Copyright 2013 Oculus VR, Inc. All Rights reserved.
-
-Use of this software is subject to the terms of the Oculus license
-agreement provided at the time of installation or download, or which
-otherwise accompanies this software in either electronic or hard copy form.
-
-*************************************************************************************/
-
-#ifndef OVR_DeviceHandle_h
-#define OVR_DeviceHandle_h
-
-#include "OVR_DeviceConstants.h"
-
-namespace OVR {
-
-class DeviceBase;
-class DeviceInfo;
-
-// Internal
-class DeviceCreateDesc;
-class DeviceEnumerationArgs;
-
-
-//-------------------------------------------------------------------------------------
-// ***** DeviceHandle
-
-// DeviceHandle references a specific device that was enumerated; it can be assigned
-// directly from DeviceEnumerator.
-//
-// Devices represented by DeviceHandle are not necessarily created or available.
-// A device may become unavailable if, for example, it its unplugged. If the device
-// is available, it can be created by calling CreateDevice.
-//
-
-class DeviceHandle
-{
- friend class DeviceManager;
- friend class DeviceManagerImpl;
- template<class B> friend class HIDDeviceImpl;
-
-public:
- DeviceHandle() : pImpl(0) { }
- DeviceHandle(const DeviceHandle& src);
- ~DeviceHandle();
-
- void operator = (const DeviceHandle& src);
-
- bool operator == (const DeviceHandle& other) const { return pImpl == other.pImpl; }
- bool operator != (const DeviceHandle& other) const { return pImpl != other.pImpl; }
-
- // operator bool() returns true if Handle/Enumerator points to a valid device.
- operator bool () const { return GetType() != Device_None; }
-
- // Returns existing device, or NULL if !IsCreated. The returned ptr is
- // addref-ed.
- DeviceBase* GetDevice_AddRef() const;
- DeviceType GetType() const;
- bool GetDeviceInfo(DeviceInfo* info) const;
- bool IsAvailable() const;
- bool IsCreated() const;
- // Returns true, if the handle contains the same device ptr
- // as specified in the parameter.
- bool IsDevice(DeviceBase*) const;
-
- // Creates a device, or returns AddRefed pointer if one is already created.
- // New devices start out with RefCount of 1.
- DeviceBase* CreateDevice();
-
- // Creates a device, or returns AddRefed pointer if one is already created.
- // New devices start out with RefCount of 1. DeviceT is used to cast the
- // DeviceBase* to a concreete type.
- template <class DeviceT>
- DeviceT* CreateDeviceTyped() const
- {
- return static_cast<DeviceT*>(DeviceHandle(*this).CreateDevice());
- }
-
- // Resets the device handle to uninitialized state.
- void Clear();
-
-protected:
- explicit DeviceHandle(DeviceCreateDesc* impl);
- bool enumerateNext(const DeviceEnumerationArgs& args);
- DeviceCreateDesc* pImpl;
-};
-
-} // namespace OVR
-
-#endif
+/************************************************************************************
+
+PublicHeader: OVR.h
+Filename : OVR_DeviceHandle.h
+Content : Handle to a device that was enumerated
+Created : February 5, 2013
+Authors : Lee Cooper
+
+Copyright : Copyright 2013 Oculus VR, Inc. All Rights reserved.
+
+Use of this software is subject to the terms of the Oculus license
+agreement provided at the time of installation or download, or which
+otherwise accompanies this software in either electronic or hard copy form.
+
+*************************************************************************************/
+
+#ifndef OVR_DeviceHandle_h
+#define OVR_DeviceHandle_h
+
+#include "OVR_DeviceConstants.h"
+
+namespace OVR {
+
+class DeviceBase;
+class DeviceInfo;
+
+// Internal
+class DeviceCreateDesc;
+class DeviceEnumerationArgs;
+
+
+//-------------------------------------------------------------------------------------
+// ***** DeviceHandle
+
+// DeviceHandle references a specific device that was enumerated; it can be assigned
+// directly from DeviceEnumerator.
+//
+// Devices represented by DeviceHandle are not necessarily created or available.
+// A device may become unavailable if, for example, it its unplugged. If the device
+// is available, it can be created by calling CreateDevice.
+//
+
+class DeviceHandle
+{
+ friend class DeviceManager;
+ friend class DeviceManagerImpl;
+ template<class B> friend class HIDDeviceImpl;
+
+public:
+ DeviceHandle() : pImpl(0) { }
+ DeviceHandle(const DeviceHandle& src);
+ ~DeviceHandle();
+
+ void operator = (const DeviceHandle& src);
+
+ bool operator == (const DeviceHandle& other) const { return pImpl == other.pImpl; }
+ bool operator != (const DeviceHandle& other) const { return pImpl != other.pImpl; }
+
+ // operator bool() returns true if Handle/Enumerator points to a valid device.
+ operator bool () const { return GetType() != Device_None; }
+
+ // Returns existing device, or NULL if !IsCreated. The returned ptr is
+ // addref-ed.
+ DeviceBase* GetDevice_AddRef() const;
+ DeviceType GetType() const;
+ bool GetDeviceInfo(DeviceInfo* info) const;
+ bool IsAvailable() const;
+ bool IsCreated() const;
+ // Returns true, if the handle contains the same device ptr
+ // as specified in the parameter.
+ bool IsDevice(DeviceBase*) const;
+
+ // Creates a device, or returns AddRefed pointer if one is already created.
+ // New devices start out with RefCount of 1.
+ DeviceBase* CreateDevice();
+
+ // Creates a device, or returns AddRefed pointer if one is already created.
+ // New devices start out with RefCount of 1. DeviceT is used to cast the
+ // DeviceBase* to a concreete type.
+ template <class DeviceT>
+ DeviceT* CreateDeviceTyped() const
+ {
+ return static_cast<DeviceT*>(DeviceHandle(*this).CreateDevice());
+ }
+
+ // Resets the device handle to uninitialized state.
+ void Clear();
+
+protected:
+ explicit DeviceHandle(DeviceCreateDesc* impl);
+ bool enumerateNext(const DeviceEnumerationArgs& args);
+ DeviceCreateDesc* pImpl;
+};
+
+} // namespace OVR
+
+#endif
diff --git a/LibOVR/Src/OVR_DeviceImpl.cpp b/LibOVR/Src/OVR_DeviceImpl.cpp
index 97cc2d4..80dc7d2 100644
--- a/LibOVR/Src/OVR_DeviceImpl.cpp
+++ b/LibOVR/Src/OVR_DeviceImpl.cpp
@@ -1,784 +1,790 @@
-/************************************************************************************
-
-Filename : OVR_DeviceImpl.h
-Content : Partial back-end independent implementation of Device interfaces
-Created : October 10, 2012
-Authors : Michael Antonov
-
-Copyright : Copyright 2012 Oculus VR, Inc. All Rights reserved.
-
-Use of this software is subject to the terms of the Oculus license
-agreement provided at the time of installation or download, or which
-otherwise accompanies this software in either electronic or hard copy form.
-
-*************************************************************************************/
-
-#include "OVR_DeviceImpl.h"
-#include "Kernel/OVR_Atomic.h"
-#include "Kernel/OVR_Log.h"
-#include "Kernel/OVR_System.h"
-
-#include "OVR_DeviceImpl.h"
-#include "OVR_SensorImpl.h"
-
-namespace OVR {
-
-
-//-------------------------------------------------------------------------------------
-// ***** SharedLock
-
-// This is a general purpose globally shared Lock implementation that should probably be
-// moved to Kernel.
-// May in theory busy spin-wait if we hit contention on first lock creation,
-// but this shouldn't matter in practice since Lock* should be cached.
-
-
-enum { LockInitMarker = 0xFFFFFFFF };
-
-Lock* SharedLock::GetLockAddRef()
-{
- int oldUseCount;
-
- do {
- oldUseCount = UseCount;
- if (oldUseCount == LockInitMarker)
- continue;
-
- if (oldUseCount == 0)
- {
- // Initialize marker
- if (AtomicOps<int>::CompareAndSet_Sync(&UseCount, 0, LockInitMarker))
- {
- Construct<Lock>(Buffer);
- do { }
- while (!AtomicOps<int>::CompareAndSet_Sync(&UseCount, LockInitMarker, 1));
- return toLock();
- }
- continue;
- }
-
- } while (!AtomicOps<int>::CompareAndSet_NoSync(&UseCount, oldUseCount, oldUseCount + 1));
-
- return toLock();
-}
-
-void SharedLock::ReleaseLock(Lock* plock)
-{
- OVR_UNUSED(plock);
- OVR_ASSERT((plock = toLock()) != 0);
-
- int oldUseCount;
-
- do {
- oldUseCount = UseCount;
- OVR_ASSERT(oldUseCount != LockInitMarker);
-
- if (oldUseCount == 1)
- {
- // Initialize marker
- if (AtomicOps<int>::CompareAndSet_Sync(&UseCount, 1, LockInitMarker))
- {
- Destruct<Lock>(toLock());
-
- do { }
- while (!AtomicOps<int>::CompareAndSet_Sync(&UseCount, LockInitMarker, 0));
-
- return;
- }
- continue;
- }
-
- } while (!AtomicOps<int>::CompareAndSet_NoSync(&UseCount, oldUseCount, oldUseCount - 1));
-}
-
-
-
-//-------------------------------------------------------------------------------------
-// ***** MessageHandler
-
-// Threading notes:
-// The OnMessage() handler and SetMessageHandler are currently synchronized
-// through a separately stored shared Lock object to avoid calling the handler
-// from background thread while it's being removed.
-
-static SharedLock MessageHandlerSharedLock;
-
-
-class MessageHandlerImpl
-{
-public:
- MessageHandlerImpl()
- : pLock(MessageHandlerSharedLock.GetLockAddRef())
- {
- }
- ~MessageHandlerImpl()
- {
- MessageHandlerSharedLock.ReleaseLock(pLock);
- pLock = 0;
- }
-
- static MessageHandlerImpl* FromHandler(MessageHandler* handler)
- { return (MessageHandlerImpl*)&handler->Internal; }
- static const MessageHandlerImpl* FromHandler(const MessageHandler* handler)
- { return (const MessageHandlerImpl*)&handler->Internal; }
-
- // This lock is held while calling a handler and when we are applied/
- // removed from a device.
- Lock* pLock;
- // List of device we are applied to.
- List<MessageHandlerRef> UseList;
-};
-
-
-MessageHandlerRef::MessageHandlerRef(DeviceBase* device)
- : pLock(MessageHandlerSharedLock.GetLockAddRef()), pDevice(device), pHandler(0)
-{
-}
-
-MessageHandlerRef::~MessageHandlerRef()
-{
- {
- Lock::Locker lockScope(pLock);
- if (pHandler)
- {
- pHandler = 0;
- RemoveNode();
- }
- }
- MessageHandlerSharedLock.ReleaseLock(pLock);
- pLock = 0;
-}
-
-void MessageHandlerRef::SetHandler(MessageHandler* handler)
-{
- OVR_ASSERT(!handler ||
- MessageHandlerImpl::FromHandler(handler)->pLock == pLock);
- Lock::Locker lockScope(pLock);
- SetHandler_NTS(handler);
-}
-
-void MessageHandlerRef::SetHandler_NTS(MessageHandler* handler)
-{
- if (pHandler != handler)
- {
- if (pHandler)
- RemoveNode();
- pHandler = handler;
-
- if (handler)
- {
- MessageHandlerImpl* handlerImpl = MessageHandlerImpl::FromHandler(handler);
- handlerImpl->UseList.PushBack(this);
- }
- // TBD: Call notifier on device?
- }
-}
-
-
-MessageHandler::MessageHandler()
-{
- OVR_COMPILER_ASSERT(sizeof(Internal) > sizeof(MessageHandlerImpl));
- Construct<MessageHandlerImpl>(Internal);
-}
-
-MessageHandler::~MessageHandler()
-{
- MessageHandlerImpl* handlerImpl = MessageHandlerImpl::FromHandler(this);
- {
- Lock::Locker lockedScope(handlerImpl->pLock);
- OVR_ASSERT_LOG(handlerImpl->UseList.IsEmpty(),
- ("~MessageHandler %p - Handler still active; call RemoveHandlerFromDevices", this));
- }
-
- Destruct<MessageHandlerImpl>(handlerImpl);
-}
-
-bool MessageHandler::IsHandlerInstalled() const
-{
- const MessageHandlerImpl* handlerImpl = MessageHandlerImpl::FromHandler(this);
- Lock::Locker lockedScope(handlerImpl->pLock);
- return handlerImpl->UseList.IsEmpty() != true;
-}
-
-
-void MessageHandler::RemoveHandlerFromDevices()
-{
- MessageHandlerImpl* handlerImpl = MessageHandlerImpl::FromHandler(this);
- Lock::Locker lockedScope(handlerImpl->pLock);
-
- while(!handlerImpl->UseList.IsEmpty())
- {
- MessageHandlerRef* use = handlerImpl->UseList.GetFirst();
- use->SetHandler_NTS(0);
- }
-}
-
-Lock* MessageHandler::GetHandlerLock() const
-{
- const MessageHandlerImpl* handlerImpl = MessageHandlerImpl::FromHandler(this);
- return handlerImpl->pLock;
-}
-
-
-//-------------------------------------------------------------------------------------
-// ***** DeviceBase
-
-
-// Delegate relevant implementation to DeviceRectord to avoid re-implementation in
-// every derived Device.
-void DeviceBase::AddRef()
-{
- getDeviceCommon()->DeviceAddRef();
-}
-void DeviceBase::Release()
-{
- getDeviceCommon()->DeviceRelease();
-}
-DeviceBase* DeviceBase::GetParent() const
-{
- return getDeviceCommon()->pParent.GetPtr();
-}
-DeviceManager* DeviceBase::GetManager() const
-{
- return getDeviceCommon()->pCreateDesc->GetManagerImpl();
-}
-
-void DeviceBase::SetMessageHandler(MessageHandler* handler)
-{
- getDeviceCommon()->HandlerRef.SetHandler(handler);
-}
-MessageHandler* DeviceBase::GetMessageHandler() const
-{
- return getDeviceCommon()->HandlerRef.GetHandler();
-}
-
-DeviceType DeviceBase::GetType() const
-{
- return getDeviceCommon()->pCreateDesc->Type;
-}
-
-bool DeviceBase::GetDeviceInfo(DeviceInfo* info) const
-{
- return getDeviceCommon()->pCreateDesc->GetDeviceInfo(info);
- //info->Name[0] = 0;
- //return false;
-}
-
-// returns the MessageHandler's lock
-Lock* DeviceBase::GetHandlerLock() const
-{
- return getDeviceCommon()->HandlerRef.GetLock();
-}
-
-// Derive DeviceManagerCreateDesc to provide abstract function implementation.
-class DeviceManagerCreateDesc : public DeviceCreateDesc
-{
-public:
- DeviceManagerCreateDesc(DeviceFactory* factory)
- : DeviceCreateDesc(factory, Device_Manager) { }
-
- // We don't need there on Manager since it isn't assigned to DeviceHandle.
- virtual DeviceCreateDesc* Clone() const { return 0; }
- virtual MatchResult MatchDevice(const DeviceCreateDesc&,
- DeviceCreateDesc**) const { return Match_None; }
- virtual DeviceBase* NewDeviceInstance() { return 0; }
- virtual bool GetDeviceInfo(DeviceInfo*) const { return false; }
-};
-
-//-------------------------------------------------------------------------------------
-// ***** DeviceManagerImpl
-
-DeviceManagerImpl::DeviceManagerImpl()
- : DeviceImpl<OVR::DeviceManager>(CreateManagerDesc(), 0)
- //,DeviceCreateDescList(pCreateDesc ? pCreateDesc->pLock : 0)
-{
- if (pCreateDesc)
- {
- pCreateDesc->pLock->pManager = this;
- }
-}
-
-DeviceManagerImpl::~DeviceManagerImpl()
-{
- // Shutdown must've been called.
- OVR_ASSERT(!pCreateDesc->pDevice);
-
- // Remove all factories
- while(!Factories.IsEmpty())
- {
- DeviceFactory* factory = Factories.GetFirst();
- factory->RemovedFromManager();
- factory->RemoveNode();
- }
-}
-
-DeviceCreateDesc* DeviceManagerImpl::CreateManagerDesc()
-{
- DeviceCreateDesc* managerDesc = new DeviceManagerCreateDesc(0);
- if (managerDesc)
- {
- managerDesc->pLock = *new DeviceManagerLock;
- }
- return managerDesc;
-}
-
-bool DeviceManagerImpl::Initialize(DeviceBase* parent)
-{
- OVR_UNUSED(parent);
- if (!pCreateDesc || !pCreateDesc->pLock)
- return false;
- return true;
-}
-
-void DeviceManagerImpl::Shutdown()
-{
- // Remove all device descriptors from list while the lock is held.
- // Some descriptors may survive longer due to handles.
- while(!Devices.IsEmpty())
- {
- DeviceCreateDesc* devDesc = Devices.GetFirst();
- OVR_ASSERT(!devDesc->pDevice); // Manager shouldn't be dying while Device exists.
- devDesc->Enumerated = false;
- devDesc->RemoveNode();
- devDesc->pNext = devDesc->pPrev = 0;
-
- if (devDesc->HandleCount == 0)
- {
- delete devDesc;
- }
- }
- Devices.Clear();
-
- // These must've been cleared by caller.
- OVR_ASSERT(pCreateDesc->pDevice == 0);
- OVR_ASSERT(pCreateDesc->pLock->pManager == 0);
-}
-
-
-// Callbacks for DeviceCreation/Release
-DeviceBase* DeviceManagerImpl::CreateDevice_MgrThread(DeviceCreateDesc* createDesc, DeviceBase* parent)
-{
- // Calls to DeviceManagerImpl::CreateDevice are enqueued with wait while holding pManager,
- // so 'this' must remain valid.
- OVR_ASSERT(createDesc->pLock->pManager);
-
- Lock::Locker devicesLock(GetLock());
-
- // If device already exists, just AddRef to it.
- if (createDesc->pDevice)
- {
- createDesc->pDevice->AddRef();
- return createDesc->pDevice;
- }
-
- if (!parent)
- parent = this;
-
- DeviceBase* device = createDesc->NewDeviceInstance();
-
- if (device)
- {
- if (device->getDeviceCommon()->Initialize(parent))
- {
- createDesc->pDevice = device;
- }
- else
- {
- // Don't go through Release() to avoid PushCall behaviour,
- // as it is not needed here.
- delete device;
- device = 0;
- }
- }
-
- return device;
-}
-
-Void DeviceManagerImpl::ReleaseDevice_MgrThread(DeviceBase* device)
-{
- // descKeepAlive will keep ManagerLock object alive as well,
- // allowing us to exit gracefully.
- Ptr<DeviceCreateDesc> descKeepAlive;
- Lock::Locker devicesLock(GetLock());
- DeviceCommon* devCommon = device->getDeviceCommon();
-
- while(1)
- {
- UInt32 refCount = devCommon->RefCount;
-
- if (refCount > 1)
- {
- if (devCommon->RefCount.CompareAndSet_NoSync(refCount, refCount-1))
- {
- // We decreented from initial count higher then 1;
- // nothing else to do.
- return 0;
- }
- }
- else if (devCommon->RefCount.CompareAndSet_NoSync(1, 0))
- {
- // { 1 -> 0 } decrement succeded. Destroy this device.
- break;
- }
- }
-
- // At this point, may be releasing the device manager itself.
- // This does not matter, however, since shutdown logic is the same
- // in both cases. DeviceManager::Shutdown with begin shutdown process for
- // the internal manager thread, which will eventually destroy itself.
- // TBD: Clean thread shutdown.
- descKeepAlive = devCommon->pCreateDesc;
- descKeepAlive->pDevice = 0;
- devCommon->Shutdown();
- delete device;
- return 0;
-}
-
-
-
-Void DeviceManagerImpl::EnumerateAllFactoryDevices()
-{
- // 1. Mark matching devices as NOT enumerated.
- // 2. Call factory to enumerate all HW devices, adding any device that
- // was not matched.
- // 3. Remove non-matching devices.
-
- Lock::Locker deviceLock(GetLock());
-
- DeviceCreateDesc* devDesc, *nextdevDesc;
-
- // 1.
- for(devDesc = Devices.GetFirst();
- !Devices.IsNull(devDesc); devDesc = devDesc->pNext)
- {
- //if (devDesc->pFactory == factory)
- devDesc->Enumerated = false;
- }
-
- // 2.
- DeviceFactory* factory = Factories.GetFirst();
- while(!Factories.IsNull(factory))
- {
- EnumerateFactoryDevices(factory);
- factory = factory->pNext;
- }
-
-
- // 3.
- for(devDesc = Devices.GetFirst();
- !Devices.IsNull(devDesc); devDesc = nextdevDesc)
- {
- // In case 'devDesc' gets removed.
- nextdevDesc = devDesc->pNext;
-
- // Note, device might be not enumerated since it is opened and
- // in use! Do NOT notify 'device removed' in this case (!AB)
- if (!devDesc->Enumerated)
- {
- // This deletes the devDesc for HandleCount == 0 due to Release in DeviceHandle.
- CallOnDeviceRemoved(devDesc);
-
- /*
- if (devDesc->HandleCount == 0)
- {
- // Device must be dead if it ever existed, since it AddRefs to us.
- // ~DeviceCreateDesc removes its node from list.
- OVR_ASSERT(!devDesc->pDevice);
- delete devDesc;
- }
- */
- }
- }
-
- return 0;
-}
-
-Ptr<DeviceCreateDesc> DeviceManagerImpl::AddDevice_NeedsLock(
- const DeviceCreateDesc& createDesc)
-{
- // If found, mark as enumerated and we are done.
- DeviceCreateDesc* descCandidate = 0;
-
- for(DeviceCreateDesc* devDesc = Devices.GetFirst();
- !Devices.IsNull(devDesc); devDesc = devDesc->pNext)
- {
- DeviceCreateDesc::MatchResult mr = devDesc->MatchDevice(createDesc, &descCandidate);
- if (mr == DeviceCreateDesc::Match_Found)
- {
- devDesc->Enumerated = true;
- if (!devDesc->pDevice)
- CallOnDeviceAdded(devDesc);
- return devDesc;
- }
- }
-
- // Update candidate (this may involve writing fields to HMDDevice createDesc).
- if (descCandidate)
- {
- bool newDevice = false;
- if (descCandidate->UpdateMatchedCandidate(createDesc, &newDevice))
- {
- descCandidate->Enumerated = true;
- if (!descCandidate->pDevice || newDevice)
- CallOnDeviceAdded(descCandidate);
- return descCandidate;
- }
- }
-
- // If not found, add new device.
- // - This stores a new descriptor with
- // {pDevice = 0, HandleCount = 1, Enumerated = true}
- DeviceCreateDesc* desc = createDesc.Clone();
- desc->pLock = pCreateDesc->pLock;
- Devices.PushBack(desc);
- desc->Enumerated = true;
-
- CallOnDeviceAdded(desc);
-
- return desc;
-}
-
-Ptr<DeviceCreateDesc> DeviceManagerImpl::FindDevice(
- const String& path,
- DeviceType deviceType)
-{
- Lock::Locker deviceLock(GetLock());
- DeviceCreateDesc* devDesc;
-
- for (devDesc = Devices.GetFirst();
- !Devices.IsNull(devDesc); devDesc = devDesc->pNext)
- {
- if ((deviceType == Device_None || deviceType == devDesc->Type) &&
- devDesc->MatchDevice(path))
- return devDesc;
- }
- return NULL;
-}
-
-Ptr<DeviceCreateDesc> DeviceManagerImpl::FindHIDDevice(const HIDDeviceDesc& hidDevDesc)
-{
- Lock::Locker deviceLock(GetLock());
- DeviceCreateDesc* devDesc;
-
- for (devDesc = Devices.GetFirst();
- !Devices.IsNull(devDesc); devDesc = devDesc->pNext)
- {
- if (devDesc->MatchHIDDevice(hidDevDesc))
- return devDesc;
- }
- return NULL;
-}
-
-void DeviceManagerImpl::DetectHIDDevice(const HIDDeviceDesc& hidDevDesc)
-{
- Lock::Locker deviceLock(GetLock());
- DeviceFactory* factory = Factories.GetFirst();
- while(!Factories.IsNull(factory))
- {
- if (factory->DetectHIDDevice(this, hidDevDesc))
- break;
- factory = factory->pNext;
- }
-
-}
-
-// Enumerates devices for a particular factory.
-Void DeviceManagerImpl::EnumerateFactoryDevices(DeviceFactory* factory)
-{
-
- class FactoryEnumerateVisitor : public DeviceFactory::EnumerateVisitor
- {
- DeviceManagerImpl* pManager;
- DeviceFactory* pFactory;
- public:
- FactoryEnumerateVisitor(DeviceManagerImpl* manager, DeviceFactory* factory)
- : pManager(manager), pFactory(factory) { }
-
- virtual void Visit(const DeviceCreateDesc& createDesc)
- {
- pManager->AddDevice_NeedsLock(createDesc);
- }
- };
-
- FactoryEnumerateVisitor newDeviceVisitor(this, factory);
- factory->EnumerateDevices(newDeviceVisitor);
-
-
- return 0;
-}
-
-
-DeviceEnumerator<> DeviceManagerImpl::EnumerateDevicesEx(const DeviceEnumerationArgs& args)
-{
- Lock::Locker deviceLock(GetLock());
-
- if (Devices.IsEmpty())
- return DeviceEnumerator<>();
-
- DeviceCreateDesc* firstDeviceDesc = Devices.GetFirst();
- DeviceEnumerator<> e = enumeratorFromHandle(DeviceHandle(firstDeviceDesc), args);
-
- if (!args.MatchRule(firstDeviceDesc->Type, firstDeviceDesc->Enumerated))
- {
- e.Next();
- }
-
- return e;
-}
-
-//-------------------------------------------------------------------------------------
-// ***** DeviceCommon
-
-void DeviceCommon::DeviceAddRef()
-{
- RefCount++;
-}
-
-void DeviceCommon::DeviceRelease()
-{
- while(1)
- {
- UInt32 refCount = RefCount;
- OVR_ASSERT(refCount > 0);
-
- if (refCount == 1)
- {
- DeviceManagerImpl* manager = pCreateDesc->GetManagerImpl();
- ThreadCommandQueue* queue = manager->GetThreadQueue();
-
- // Enqueue ReleaseDevice for {1 -> 0} transition with no wait.
- // We pass our reference ownership into the queue to destroy.
- // It's in theory possible for another thread to re-steal our device reference,
- // but that is checked for atomically in DeviceManagerImpl::ReleaseDevice.
- if (!queue->PushCall(manager, &DeviceManagerImpl::ReleaseDevice_MgrThread,
- pCreateDesc->pDevice))
- {
- // PushCall shouldn't fail because background thread runs while manager is
- // alive and we are holding Manager alive through pParent chain.
- OVR_ASSERT(false);
- }
-
- // Warning! At his point everything, including manager, may be dead.
- break;
- }
- else if (RefCount.CompareAndSet_NoSync(refCount, refCount-1))
- {
- break;
- }
- }
-}
-
-
-
-//-------------------------------------------------------------------------------------
-// ***** DeviceCreateDesc
-
-
-void DeviceCreateDesc::AddRef()
-{
- // Technically, HandleCount { 0 -> 1 } transition can only happen during Lock,
- // but we leave this to caller to worry about (happens during enumeration).
- HandleCount++;
-}
-
-void DeviceCreateDesc::Release()
-{
- while(1)
- {
- UInt32 handleCount = HandleCount;
- // HandleCount must obviously be >= 1, since we are releasing it.
- OVR_ASSERT(handleCount > 0);
-
- // {1 -> 0} transition may cause us to be destroyed, so require a lock.
- if (handleCount == 1)
- {
- Ptr<DeviceManagerLock> lockKeepAlive;
- Lock::Locker deviceLockScope(GetLock());
-
- if (!HandleCount.CompareAndSet_NoSync(handleCount, 0))
- continue;
-
- OVR_ASSERT(pDevice == 0);
-
- // Destroy *this if the manager was destroyed already, or Enumerated
- // is false (device no longer available).
- if (!GetManagerImpl() || !Enumerated)
- {
- lockKeepAlive = pLock;
-
- // Remove from manager list (only matters for !Enumerated).
- if (pNext)
- {
- RemoveNode();
- pNext = pPrev = 0;
- }
-
- delete this;
- }
-
- // Available DeviceCreateDesc may survive with { HandleCount == 0 },
- // in case it might be enumerated again later.
- break;
- }
- else if (HandleCount.CompareAndSet_NoSync(handleCount, handleCount-1))
- {
- break;
- }
- }
-}
-
-HMDDevice* HMDDevice::Disconnect(SensorDevice* psensor)
-{
- if (!psensor)
- return NULL;
-
- OVR::DeviceManager* manager = GetManager();
- if (manager)
- {
- //DeviceManagerImpl* mgrImpl = static_cast<DeviceManagerImpl*>(manager);
- Ptr<DeviceCreateDesc> desc = getDeviceCommon()->pCreateDesc;
- if (desc)
- {
- class Visitor : public DeviceFactory::EnumerateVisitor
- {
- Ptr<DeviceCreateDesc> Desc;
- public:
- Visitor(DeviceCreateDesc* desc) : Desc(desc) {}
- virtual void Visit(const DeviceCreateDesc& createDesc)
- {
- Lock::Locker lock(Desc->GetLock());
- Desc->UpdateMatchedCandidate(createDesc);
- }
- } visitor(desc);
- //SensorDeviceImpl* sImpl = static_cast<SensorDeviceImpl*>(psensor);
-
- SensorDisplayInfoImpl displayInfo;
-
- if (psensor->GetFeatureReport(displayInfo.Buffer, SensorDisplayInfoImpl::PacketSize))
- {
- displayInfo.Unpack();
-
- // If we got display info, try to match / create HMDDevice as well
- // so that sensor settings give preference.
- if (displayInfo.DistortionType & SensorDisplayInfoImpl::Mask_BaseFmt)
- {
- SensorDeviceImpl::EnumerateHMDFromSensorDisplayInfo(displayInfo, visitor);
- }
- }
- }
- }
- return this;
-}
-
-bool HMDDevice::IsDisconnected() const
-{
- OVR::HMDInfo info;
- GetDeviceInfo(&info);
- // if strlen(info.DisplayDeviceName) == 0 then
- // this HMD is 'fake' (created using sensor).
- return (strlen(info.DisplayDeviceName) == 0);
-}
-
-
-} // namespace OVR
-
+/************************************************************************************
+
+Filename : OVR_DeviceImpl.h
+Content : Partial back-end independent implementation of Device interfaces
+Created : October 10, 2012
+Authors : Michael Antonov
+
+Copyright : Copyright 2012 Oculus VR, Inc. All Rights reserved.
+
+Use of this software is subject to the terms of the Oculus license
+agreement provided at the time of installation or download, or which
+otherwise accompanies this software in either electronic or hard copy form.
+
+*************************************************************************************/
+
+#include "OVR_DeviceImpl.h"
+#include "Kernel/OVR_Atomic.h"
+#include "Kernel/OVR_Log.h"
+#include "Kernel/OVR_System.h"
+
+#include "OVR_DeviceImpl.h"
+#include "OVR_SensorImpl.h"
+#include "OVR_Profile.h"
+
+namespace OVR {
+
+
+//-------------------------------------------------------------------------------------
+// ***** SharedLock
+
+// This is a general purpose globally shared Lock implementation that should probably be
+// moved to Kernel.
+// May in theory busy spin-wait if we hit contention on first lock creation,
+// but this shouldn't matter in practice since Lock* should be cached.
+
+
+enum { LockInitMarker = 0xFFFFFFFF };
+
+Lock* SharedLock::GetLockAddRef()
+{
+ int oldUseCount;
+
+ do {
+ oldUseCount = UseCount;
+ if (oldUseCount == LockInitMarker)
+ continue;
+
+ if (oldUseCount == 0)
+ {
+ // Initialize marker
+ if (AtomicOps<int>::CompareAndSet_Sync(&UseCount, 0, LockInitMarker))
+ {
+ Construct<Lock>(Buffer);
+ do { }
+ while (!AtomicOps<int>::CompareAndSet_Sync(&UseCount, LockInitMarker, 1));
+ return toLock();
+ }
+ continue;
+ }
+
+ } while (!AtomicOps<int>::CompareAndSet_NoSync(&UseCount, oldUseCount, oldUseCount + 1));
+
+ return toLock();
+}
+
+void SharedLock::ReleaseLock(Lock* plock)
+{
+ OVR_UNUSED(plock);
+ OVR_ASSERT(plock == toLock());
+
+ int oldUseCount;
+
+ do {
+ oldUseCount = UseCount;
+ OVR_ASSERT(oldUseCount != LockInitMarker);
+
+ if (oldUseCount == 1)
+ {
+ // Initialize marker
+ if (AtomicOps<int>::CompareAndSet_Sync(&UseCount, 1, LockInitMarker))
+ {
+ Destruct<Lock>(toLock());
+
+ do { }
+ while (!AtomicOps<int>::CompareAndSet_Sync(&UseCount, LockInitMarker, 0));
+
+ return;
+ }
+ continue;
+ }
+
+ } while (!AtomicOps<int>::CompareAndSet_NoSync(&UseCount, oldUseCount, oldUseCount - 1));
+}
+
+
+
+//-------------------------------------------------------------------------------------
+// ***** MessageHandler
+
+// Threading notes:
+// The OnMessage() handler and SetMessageHandler are currently synchronized
+// through a separately stored shared Lock object to avoid calling the handler
+// from background thread while it's being removed.
+
+static SharedLock MessageHandlerSharedLock;
+
+
+class MessageHandlerImpl
+{
+public:
+ MessageHandlerImpl()
+ : pLock(MessageHandlerSharedLock.GetLockAddRef())
+ {
+ }
+ ~MessageHandlerImpl()
+ {
+ MessageHandlerSharedLock.ReleaseLock(pLock);
+ pLock = 0;
+ }
+
+ static MessageHandlerImpl* FromHandler(MessageHandler* handler)
+ { return (MessageHandlerImpl*)&handler->Internal; }
+ static const MessageHandlerImpl* FromHandler(const MessageHandler* handler)
+ { return (const MessageHandlerImpl*)&handler->Internal; }
+
+ // This lock is held while calling a handler and when we are applied/
+ // removed from a device.
+ Lock* pLock;
+ // List of device we are applied to.
+ List<MessageHandlerRef> UseList;
+};
+
+
+MessageHandlerRef::MessageHandlerRef(DeviceBase* device)
+ : pLock(MessageHandlerSharedLock.GetLockAddRef()), pDevice(device), pHandler(0)
+{
+}
+
+MessageHandlerRef::~MessageHandlerRef()
+{
+ {
+ Lock::Locker lockScope(pLock);
+ if (pHandler)
+ {
+ pHandler = 0;
+ RemoveNode();
+ }
+ }
+ MessageHandlerSharedLock.ReleaseLock(pLock);
+ pLock = 0;
+}
+
+void MessageHandlerRef::SetHandler(MessageHandler* handler)
+{
+ OVR_ASSERT(!handler ||
+ MessageHandlerImpl::FromHandler(handler)->pLock == pLock);
+ Lock::Locker lockScope(pLock);
+ SetHandler_NTS(handler);
+}
+
+void MessageHandlerRef::SetHandler_NTS(MessageHandler* handler)
+{
+ if (pHandler != handler)
+ {
+ if (pHandler)
+ RemoveNode();
+ pHandler = handler;
+
+ if (handler)
+ {
+ MessageHandlerImpl* handlerImpl = MessageHandlerImpl::FromHandler(handler);
+ handlerImpl->UseList.PushBack(this);
+ }
+ // TBD: Call notifier on device?
+ }
+}
+
+
+MessageHandler::MessageHandler()
+{
+ OVR_COMPILER_ASSERT(sizeof(Internal) > sizeof(MessageHandlerImpl));
+ Construct<MessageHandlerImpl>(Internal);
+}
+
+MessageHandler::~MessageHandler()
+{
+ MessageHandlerImpl* handlerImpl = MessageHandlerImpl::FromHandler(this);
+ {
+ Lock::Locker lockedScope(handlerImpl->pLock);
+ OVR_ASSERT_LOG(handlerImpl->UseList.IsEmpty(),
+ ("~MessageHandler %p - Handler still active; call RemoveHandlerFromDevices", this));
+ }
+
+ Destruct<MessageHandlerImpl>(handlerImpl);
+}
+
+bool MessageHandler::IsHandlerInstalled() const
+{
+ const MessageHandlerImpl* handlerImpl = MessageHandlerImpl::FromHandler(this);
+ Lock::Locker lockedScope(handlerImpl->pLock);
+ return handlerImpl->UseList.IsEmpty() != true;
+}
+
+
+void MessageHandler::RemoveHandlerFromDevices()
+{
+ MessageHandlerImpl* handlerImpl = MessageHandlerImpl::FromHandler(this);
+ Lock::Locker lockedScope(handlerImpl->pLock);
+
+ while(!handlerImpl->UseList.IsEmpty())
+ {
+ MessageHandlerRef* use = handlerImpl->UseList.GetFirst();
+ use->SetHandler_NTS(0);
+ }
+}
+
+Lock* MessageHandler::GetHandlerLock() const
+{
+ const MessageHandlerImpl* handlerImpl = MessageHandlerImpl::FromHandler(this);
+ return handlerImpl->pLock;
+}
+
+
+//-------------------------------------------------------------------------------------
+// ***** DeviceBase
+
+
+// Delegate relevant implementation to DeviceRectord to avoid re-implementation in
+// every derived Device.
+void DeviceBase::AddRef()
+{
+ getDeviceCommon()->DeviceAddRef();
+}
+void DeviceBase::Release()
+{
+ getDeviceCommon()->DeviceRelease();
+}
+DeviceBase* DeviceBase::GetParent() const
+{
+ return getDeviceCommon()->pParent.GetPtr();
+}
+DeviceManager* DeviceBase::GetManager() const
+{
+ return getDeviceCommon()->pCreateDesc->GetManagerImpl();
+}
+
+void DeviceBase::SetMessageHandler(MessageHandler* handler)
+{
+ getDeviceCommon()->HandlerRef.SetHandler(handler);
+}
+MessageHandler* DeviceBase::GetMessageHandler() const
+{
+ return getDeviceCommon()->HandlerRef.GetHandler();
+}
+
+DeviceType DeviceBase::GetType() const
+{
+ return getDeviceCommon()->pCreateDesc->Type;
+}
+
+bool DeviceBase::GetDeviceInfo(DeviceInfo* info) const
+{
+ return getDeviceCommon()->pCreateDesc->GetDeviceInfo(info);
+ //info->Name[0] = 0;
+ //return false;
+}
+
+// returns the MessageHandler's lock
+Lock* DeviceBase::GetHandlerLock() const
+{
+ return getDeviceCommon()->HandlerRef.GetLock();
+}
+
+// Derive DeviceManagerCreateDesc to provide abstract function implementation.
+class DeviceManagerCreateDesc : public DeviceCreateDesc
+{
+public:
+ DeviceManagerCreateDesc(DeviceFactory* factory)
+ : DeviceCreateDesc(factory, Device_Manager) { }
+
+ // We don't need there on Manager since it isn't assigned to DeviceHandle.
+ virtual DeviceCreateDesc* Clone() const { return 0; }
+ virtual MatchResult MatchDevice(const DeviceCreateDesc&,
+ DeviceCreateDesc**) const { return Match_None; }
+ virtual DeviceBase* NewDeviceInstance() { return 0; }
+ virtual bool GetDeviceInfo(DeviceInfo*) const { return false; }
+};
+
+//-------------------------------------------------------------------------------------
+// ***** DeviceManagerImpl
+
+DeviceManagerImpl::DeviceManagerImpl()
+ : DeviceImpl<OVR::DeviceManager>(CreateManagerDesc(), 0)
+ //,DeviceCreateDescList(pCreateDesc ? pCreateDesc->pLock : 0)
+{
+ if (pCreateDesc)
+ {
+ pCreateDesc->pLock->pManager = this;
+ }
+}
+
+DeviceManagerImpl::~DeviceManagerImpl()
+{
+ // Shutdown must've been called.
+ OVR_ASSERT(!pCreateDesc->pDevice);
+
+ // Remove all factories
+ while(!Factories.IsEmpty())
+ {
+ DeviceFactory* factory = Factories.GetFirst();
+ factory->RemovedFromManager();
+ factory->RemoveNode();
+ }
+}
+
+DeviceCreateDesc* DeviceManagerImpl::CreateManagerDesc()
+{
+ DeviceCreateDesc* managerDesc = new DeviceManagerCreateDesc(0);
+ if (managerDesc)
+ {
+ managerDesc->pLock = *new DeviceManagerLock;
+ }
+ return managerDesc;
+}
+
+bool DeviceManagerImpl::Initialize(DeviceBase* parent)
+{
+ OVR_UNUSED(parent);
+ if (!pCreateDesc || !pCreateDesc->pLock)
+ return false;
+
+ pProfileManager = *ProfileManager::Create();
+
+ return true;
+}
+
+void DeviceManagerImpl::Shutdown()
+{
+ // Remove all device descriptors from list while the lock is held.
+ // Some descriptors may survive longer due to handles.
+ while(!Devices.IsEmpty())
+ {
+ DeviceCreateDesc* devDesc = Devices.GetFirst();
+ OVR_ASSERT(!devDesc->pDevice); // Manager shouldn't be dying while Device exists.
+ devDesc->Enumerated = false;
+ devDesc->RemoveNode();
+ devDesc->pNext = devDesc->pPrev = 0;
+
+ if (devDesc->HandleCount == 0)
+ {
+ delete devDesc;
+ }
+ }
+ Devices.Clear();
+
+ // These must've been cleared by caller.
+ OVR_ASSERT(pCreateDesc->pDevice == 0);
+ OVR_ASSERT(pCreateDesc->pLock->pManager == 0);
+
+ pProfileManager.Clear();
+}
+
+
+// Callbacks for DeviceCreation/Release
+DeviceBase* DeviceManagerImpl::CreateDevice_MgrThread(DeviceCreateDesc* createDesc, DeviceBase* parent)
+{
+ // Calls to DeviceManagerImpl::CreateDevice are enqueued with wait while holding pManager,
+ // so 'this' must remain valid.
+ OVR_ASSERT(createDesc->pLock->pManager);
+
+ Lock::Locker devicesLock(GetLock());
+
+ // If device already exists, just AddRef to it.
+ if (createDesc->pDevice)
+ {
+ createDesc->pDevice->AddRef();
+ return createDesc->pDevice;
+ }
+
+ if (!parent)
+ parent = this;
+
+ DeviceBase* device = createDesc->NewDeviceInstance();
+
+ if (device)
+ {
+ if (device->getDeviceCommon()->Initialize(parent))
+ {
+ createDesc->pDevice = device;
+ }
+ else
+ {
+ // Don't go through Release() to avoid PushCall behaviour,
+ // as it is not needed here.
+ delete device;
+ device = 0;
+ }
+ }
+
+ return device;
+}
+
+Void DeviceManagerImpl::ReleaseDevice_MgrThread(DeviceBase* device)
+{
+ // descKeepAlive will keep ManagerLock object alive as well,
+ // allowing us to exit gracefully.
+ Ptr<DeviceCreateDesc> descKeepAlive;
+ Lock::Locker devicesLock(GetLock());
+ DeviceCommon* devCommon = device->getDeviceCommon();
+
+ while(1)
+ {
+ UInt32 refCount = devCommon->RefCount;
+
+ if (refCount > 1)
+ {
+ if (devCommon->RefCount.CompareAndSet_NoSync(refCount, refCount-1))
+ {
+ // We decreented from initial count higher then 1;
+ // nothing else to do.
+ return 0;
+ }
+ }
+ else if (devCommon->RefCount.CompareAndSet_NoSync(1, 0))
+ {
+ // { 1 -> 0 } decrement succeded. Destroy this device.
+ break;
+ }
+ }
+
+ // At this point, may be releasing the device manager itself.
+ // This does not matter, however, since shutdown logic is the same
+ // in both cases. DeviceManager::Shutdown with begin shutdown process for
+ // the internal manager thread, which will eventually destroy itself.
+ // TBD: Clean thread shutdown.
+ descKeepAlive = devCommon->pCreateDesc;
+ descKeepAlive->pDevice = 0;
+ devCommon->Shutdown();
+ delete device;
+ return 0;
+}
+
+
+
+Void DeviceManagerImpl::EnumerateAllFactoryDevices()
+{
+ // 1. Mark matching devices as NOT enumerated.
+ // 2. Call factory to enumerate all HW devices, adding any device that
+ // was not matched.
+ // 3. Remove non-matching devices.
+
+ Lock::Locker deviceLock(GetLock());
+
+ DeviceCreateDesc* devDesc, *nextdevDesc;
+
+ // 1.
+ for(devDesc = Devices.GetFirst();
+ !Devices.IsNull(devDesc); devDesc = devDesc->pNext)
+ {
+ //if (devDesc->pFactory == factory)
+ devDesc->Enumerated = false;
+ }
+
+ // 2.
+ DeviceFactory* factory = Factories.GetFirst();
+ while(!Factories.IsNull(factory))
+ {
+ EnumerateFactoryDevices(factory);
+ factory = factory->pNext;
+ }
+
+
+ // 3.
+ for(devDesc = Devices.GetFirst();
+ !Devices.IsNull(devDesc); devDesc = nextdevDesc)
+ {
+ // In case 'devDesc' gets removed.
+ nextdevDesc = devDesc->pNext;
+
+ // Note, device might be not enumerated since it is opened and
+ // in use! Do NOT notify 'device removed' in this case (!AB)
+ if (!devDesc->Enumerated)
+ {
+ // This deletes the devDesc for HandleCount == 0 due to Release in DeviceHandle.
+ CallOnDeviceRemoved(devDesc);
+
+ /*
+ if (devDesc->HandleCount == 0)
+ {
+ // Device must be dead if it ever existed, since it AddRefs to us.
+ // ~DeviceCreateDesc removes its node from list.
+ OVR_ASSERT(!devDesc->pDevice);
+ delete devDesc;
+ }
+ */
+ }
+ }
+
+ return 0;
+}
+
+Ptr<DeviceCreateDesc> DeviceManagerImpl::AddDevice_NeedsLock(
+ const DeviceCreateDesc& createDesc)
+{
+ // If found, mark as enumerated and we are done.
+ DeviceCreateDesc* descCandidate = 0;
+
+ for(DeviceCreateDesc* devDesc = Devices.GetFirst();
+ !Devices.IsNull(devDesc); devDesc = devDesc->pNext)
+ {
+ DeviceCreateDesc::MatchResult mr = devDesc->MatchDevice(createDesc, &descCandidate);
+ if (mr == DeviceCreateDesc::Match_Found)
+ {
+ devDesc->Enumerated = true;
+ if (!devDesc->pDevice)
+ CallOnDeviceAdded(devDesc);
+ return devDesc;
+ }
+ }
+
+ // Update candidate (this may involve writing fields to HMDDevice createDesc).
+ if (descCandidate)
+ {
+ bool newDevice = false;
+ if (descCandidate->UpdateMatchedCandidate(createDesc, &newDevice))
+ {
+ descCandidate->Enumerated = true;
+ if (!descCandidate->pDevice || newDevice)
+ CallOnDeviceAdded(descCandidate);
+ return descCandidate;
+ }
+ }
+
+ // If not found, add new device.
+ // - This stores a new descriptor with
+ // {pDevice = 0, HandleCount = 1, Enumerated = true}
+ DeviceCreateDesc* desc = createDesc.Clone();
+ desc->pLock = pCreateDesc->pLock;
+ Devices.PushBack(desc);
+ desc->Enumerated = true;
+
+ CallOnDeviceAdded(desc);
+
+ return desc;
+}
+
+Ptr<DeviceCreateDesc> DeviceManagerImpl::FindDevice(
+ const String& path,
+ DeviceType deviceType)
+{
+ Lock::Locker deviceLock(GetLock());
+ DeviceCreateDesc* devDesc;
+
+ for (devDesc = Devices.GetFirst();
+ !Devices.IsNull(devDesc); devDesc = devDesc->pNext)
+ {
+ if ((deviceType == Device_None || deviceType == devDesc->Type) &&
+ devDesc->MatchDevice(path))
+ return devDesc;
+ }
+ return NULL;
+}
+
+Ptr<DeviceCreateDesc> DeviceManagerImpl::FindHIDDevice(const HIDDeviceDesc& hidDevDesc)
+{
+ Lock::Locker deviceLock(GetLock());
+ DeviceCreateDesc* devDesc;
+
+ for (devDesc = Devices.GetFirst();
+ !Devices.IsNull(devDesc); devDesc = devDesc->pNext)
+ {
+ if (devDesc->MatchHIDDevice(hidDevDesc))
+ return devDesc;
+ }
+ return NULL;
+}
+
+void DeviceManagerImpl::DetectHIDDevice(const HIDDeviceDesc& hidDevDesc)
+{
+ Lock::Locker deviceLock(GetLock());
+ DeviceFactory* factory = Factories.GetFirst();
+ while(!Factories.IsNull(factory))
+ {
+ if (factory->DetectHIDDevice(this, hidDevDesc))
+ break;
+ factory = factory->pNext;
+ }
+
+}
+
+// Enumerates devices for a particular factory.
+Void DeviceManagerImpl::EnumerateFactoryDevices(DeviceFactory* factory)
+{
+
+ class FactoryEnumerateVisitor : public DeviceFactory::EnumerateVisitor
+ {
+ DeviceManagerImpl* pManager;
+ DeviceFactory* pFactory;
+ public:
+ FactoryEnumerateVisitor(DeviceManagerImpl* manager, DeviceFactory* factory)
+ : pManager(manager), pFactory(factory) { }
+
+ virtual void Visit(const DeviceCreateDesc& createDesc)
+ {
+ pManager->AddDevice_NeedsLock(createDesc);
+ }
+ };
+
+ FactoryEnumerateVisitor newDeviceVisitor(this, factory);
+ factory->EnumerateDevices(newDeviceVisitor);
+
+
+ return 0;
+}
+
+
+DeviceEnumerator<> DeviceManagerImpl::EnumerateDevicesEx(const DeviceEnumerationArgs& args)
+{
+ Lock::Locker deviceLock(GetLock());
+
+ if (Devices.IsEmpty())
+ return DeviceEnumerator<>();
+
+ DeviceCreateDesc* firstDeviceDesc = Devices.GetFirst();
+ DeviceEnumerator<> e = enumeratorFromHandle(DeviceHandle(firstDeviceDesc), args);
+
+ if (!args.MatchRule(firstDeviceDesc->Type, firstDeviceDesc->Enumerated))
+ {
+ e.Next();
+ }
+
+ return e;
+}
+
+//-------------------------------------------------------------------------------------
+// ***** DeviceCommon
+
+void DeviceCommon::DeviceAddRef()
+{
+ RefCount++;
+}
+
+void DeviceCommon::DeviceRelease()
+{
+ while(1)
+ {
+ UInt32 refCount = RefCount;
+ OVR_ASSERT(refCount > 0);
+
+ if (refCount == 1)
+ {
+ DeviceManagerImpl* manager = pCreateDesc->GetManagerImpl();
+ ThreadCommandQueue* queue = manager->GetThreadQueue();
+
+ // Enqueue ReleaseDevice for {1 -> 0} transition with no wait.
+ // We pass our reference ownership into the queue to destroy.
+ // It's in theory possible for another thread to re-steal our device reference,
+ // but that is checked for atomically in DeviceManagerImpl::ReleaseDevice.
+ if (!queue->PushCall(manager, &DeviceManagerImpl::ReleaseDevice_MgrThread,
+ pCreateDesc->pDevice))
+ {
+ // PushCall shouldn't fail because background thread runs while manager is
+ // alive and we are holding Manager alive through pParent chain.
+ OVR_ASSERT(false);
+ }
+
+ // Warning! At his point everything, including manager, may be dead.
+ break;
+ }
+ else if (RefCount.CompareAndSet_NoSync(refCount, refCount-1))
+ {
+ break;
+ }
+ }
+}
+
+
+
+//-------------------------------------------------------------------------------------
+// ***** DeviceCreateDesc
+
+
+void DeviceCreateDesc::AddRef()
+{
+ // Technically, HandleCount { 0 -> 1 } transition can only happen during Lock,
+ // but we leave this to caller to worry about (happens during enumeration).
+ HandleCount++;
+}
+
+void DeviceCreateDesc::Release()
+{
+ while(1)
+ {
+ UInt32 handleCount = HandleCount;
+ // HandleCount must obviously be >= 1, since we are releasing it.
+ OVR_ASSERT(handleCount > 0);
+
+ // {1 -> 0} transition may cause us to be destroyed, so require a lock.
+ if (handleCount == 1)
+ {
+ Ptr<DeviceManagerLock> lockKeepAlive;
+ Lock::Locker deviceLockScope(GetLock());
+
+ if (!HandleCount.CompareAndSet_NoSync(handleCount, 0))
+ continue;
+
+ OVR_ASSERT(pDevice == 0);
+
+ // Destroy *this if the manager was destroyed already, or Enumerated
+ // is false (device no longer available).
+ if (!GetManagerImpl() || !Enumerated)
+ {
+ lockKeepAlive = pLock;
+
+ // Remove from manager list (only matters for !Enumerated).
+ if (pNext)
+ {
+ RemoveNode();
+ pNext = pPrev = 0;
+ }
+
+ delete this;
+ }
+
+ // Available DeviceCreateDesc may survive with { HandleCount == 0 },
+ // in case it might be enumerated again later.
+ break;
+ }
+ else if (HandleCount.CompareAndSet_NoSync(handleCount, handleCount-1))
+ {
+ break;
+ }
+ }
+}
+
+HMDDevice* HMDDevice::Disconnect(SensorDevice* psensor)
+{
+ if (!psensor)
+ return NULL;
+
+ OVR::DeviceManager* manager = GetManager();
+ if (manager)
+ {
+ //DeviceManagerImpl* mgrImpl = static_cast<DeviceManagerImpl*>(manager);
+ Ptr<DeviceCreateDesc> desc = getDeviceCommon()->pCreateDesc;
+ if (desc)
+ {
+ class Visitor : public DeviceFactory::EnumerateVisitor
+ {
+ Ptr<DeviceCreateDesc> Desc;
+ public:
+ Visitor(DeviceCreateDesc* desc) : Desc(desc) {}
+ virtual void Visit(const DeviceCreateDesc& createDesc)
+ {
+ Lock::Locker lock(Desc->GetLock());
+ Desc->UpdateMatchedCandidate(createDesc);
+ }
+ } visitor(desc);
+ //SensorDeviceImpl* sImpl = static_cast<SensorDeviceImpl*>(psensor);
+
+ SensorDisplayInfoImpl displayInfo;
+
+ if (psensor->GetFeatureReport(displayInfo.Buffer, SensorDisplayInfoImpl::PacketSize))
+ {
+ displayInfo.Unpack();
+
+ // If we got display info, try to match / create HMDDevice as well
+ // so that sensor settings give preference.
+ if (displayInfo.DistortionType & SensorDisplayInfoImpl::Mask_BaseFmt)
+ {
+ SensorDeviceImpl::EnumerateHMDFromSensorDisplayInfo(displayInfo, visitor);
+ }
+ }
+ }
+ }
+ return this;
+}
+
+bool HMDDevice::IsDisconnected() const
+{
+ OVR::HMDInfo info;
+ GetDeviceInfo(&info);
+ // if strlen(info.DisplayDeviceName) == 0 then
+ // this HMD is 'fake' (created using sensor).
+ return (strlen(info.DisplayDeviceName) == 0);
+}
+
+
+} // namespace OVR
+
diff --git a/LibOVR/Src/OVR_DeviceImpl.h b/LibOVR/Src/OVR_DeviceImpl.h
index 8b7bf0a..2273d3d 100644
--- a/LibOVR/Src/OVR_DeviceImpl.h
+++ b/LibOVR/Src/OVR_DeviceImpl.h
@@ -1,425 +1,432 @@
-/************************************************************************************
-
-Filename : OVR_DeviceImpl.h
-Content : Partial back-end independent implementation of Device interfaces
-Created : October 10, 2012
-Authors : Michael Antonov
-
-Copyright : Copyright 2012 Oculus VR, Inc. All Rights reserved.
-
-Use of this software is subject to the terms of the Oculus license
-agreement provided at the time of installation or download, or which
-otherwise accompanies this software in either electronic or hard copy form.
-
-*************************************************************************************/
-
-#ifndef OVR_DeviceImpl_h
-#define OVR_DeviceImpl_h
-
-#include "OVR_Device.h"
-#include "Kernel/OVR_Atomic.h"
-#include "Kernel/OVR_Log.h"
-#include "Kernel/OVR_System.h"
-
-#include "Kernel/OVR_Threads.h"
-#include "OVR_ThreadCommandQueue.h"
-#include "OVR_HIDDevice.h"
-
-namespace OVR {
-
-class DeviceManagerImpl;
-class DeviceFactory;
-
-enum
-{
- Oculus_VendorId = 0x2833
-};
-
-//-------------------------------------------------------------------------------------
-// Globally shared Lock implementation used for MessageHandlers.
-
-class SharedLock
-{
-public:
-
- Lock* GetLockAddRef();
- void ReleaseLock(Lock* plock);
-
-private:
- Lock* toLock() { return (Lock*)Buffer; }
-
- // UseCount and max alignment.
- volatile int UseCount;
- UInt64 Buffer[(sizeof(Lock)+sizeof(UInt64)-1)/sizeof(UInt64)];
-};
-
-
-// Wrapper for MessageHandler that includes synchronization logic.
-// References to MessageHandlers are organized in a list to allow for them to
-// easily removed with MessageHandler::RemoveAllHandlers.
-class MessageHandlerRef : public ListNode<MessageHandlerRef>
-{
-public:
- MessageHandlerRef(DeviceBase* device);
- ~MessageHandlerRef();
-
- void SetHandler(MessageHandler* hander);
-
- // Not-thread-safe version
- void SetHandler_NTS(MessageHandler* hander);
-
- void Call(const Message& msg)
- {
- Lock::Locker lockScope(pLock);
- if (pHandler)
- pHandler->OnMessage(msg);
- }
-
- Lock* GetLock() const { return pLock; }
-
- // GetHandler() is not thread safe if used out of order across threads; nothing can be done
- // about that.
- MessageHandler* GetHandler() const { return pHandler; }
- DeviceBase* GetDevice() const { return pDevice; }
-
-private:
- Lock* pLock; // Cached global handler lock.
- DeviceBase* pDevice;
- MessageHandler* pHandler;
-};
-
-
-
-//-------------------------------------------------------------------------------------
-
-// DeviceManagerLock is a synchronization lock used by DeviceManager for Devices
-// and is allocated separately for potentially longer lifetime.
-//
-// DeviceManagerLock is used for all of the following:
-// - Adding/removing devices
-// - Reporting manager lifetime (pManager != 0) for DeviceHandles
-// - Protecting device creation/shutdown.
-
-class DeviceManagerLock : public RefCountBase<DeviceManagerLock>
-{
-public:
- Lock CreateLock;
- DeviceManagerImpl* pManager;
-
- DeviceManagerLock() : pManager(0) { }
-};
-
-
-// DeviceCreateDesc provides all of the information needed to create any device, a derived
-// instance of this class is created by DeviceFactory during enumeration.
-// - DeviceCreateDesc may or may not be a part of DeviceManager::Devices list (check pNext != 0).
-// - Referenced and kept alive by DeviceHandle.
-
-class DeviceCreateDesc : public ListNode<DeviceCreateDesc>, public NewOverrideBase
-{
- void operator = (const DeviceCreateDesc&) { } // Assign not supported; suppress MSVC warning.
-public:
- DeviceCreateDesc(DeviceFactory* factory, DeviceType type)
- : pFactory(factory), Type(type), pLock(0), HandleCount(0), pDevice(0), Enumerated(true)
- {
- pNext = pPrev = 0;
- }
-
- virtual ~DeviceCreateDesc()
- {
- OVR_ASSERT(!pDevice);
- if (pNext)
- RemoveNode();
- }
-
- DeviceManagerImpl* GetManagerImpl() { return pLock->pManager; }
- Lock* GetLock() const { return &pLock->CreateLock; }
-
- // DeviceCreateDesc reference counting is tied to Devices list management,
- // see comments for HandleCount.
- void AddRef();
- void Release();
-
-
- // *** Device creation/matching Interface
-
-
- // Cloning copies us to an allocated object when new device is enumerated.
- virtual DeviceCreateDesc* Clone() const = 0;
- // Creates a new device instance without Initializing it; the
- // later is done my Initialize()/Shutdown() methods of the device itself.
- virtual DeviceBase* NewDeviceInstance() = 0;
- // Override to return device-specific info.
- virtual bool GetDeviceInfo(DeviceInfo* info) const = 0;
-
-
- enum MatchResult
- {
- Match_None,
- Match_Found,
- Match_Candidate
- };
-
- // Override to return Match_Found if descriptor matches our device.
- // Match_Candidate can be returned, with pcandicate update, if this may be a match
- // but more searching is necessary. If this is the case UpdateMatchedCandidate will be called.
- virtual MatchResult MatchDevice(const DeviceCreateDesc& other,
- DeviceCreateDesc** pcandidate) const = 0;
-
- // Called for matched candidate after all potential matches are iterated.
- // Used to update HMDevice creation arguments from Sensor.
- // Optional return param 'newDeviceFlag' will be set to true if the
- // 'desc' refers to a new device; false, otherwise.
- // Return 'false' to create new object, 'true' if done with this argument.
- virtual bool UpdateMatchedCandidate(
- const DeviceCreateDesc& desc, bool* newDeviceFlag = NULL)
- { OVR_UNUSED2(desc, newDeviceFlag); return false; }
-
- // Matches HID device to the descriptor.
- virtual bool MatchHIDDevice(const HIDDeviceDesc&) const { return false; }
-
- // Matches device by path.
- virtual bool MatchDevice(const String& /*path*/) { return false; }
-//protected:
- DeviceFactory* const pFactory;
- const DeviceType Type;
-
- // List in which this descriptor lives. pList->CreateLock required if added/removed.
- Ptr<DeviceManagerLock> pLock;
-
- // Strong references to us: Incremented by Device, DeviceHandles & Enumerators.
- // May be 0 if device not created and there are no handles.
- // Following transitions require pList->CreateLock:
- // {1 -> 0}: May delete & remove handle if no longer available.
- // {0 -> 1}: Device creation is only possible if manager is still alive.
- AtomicInt<UInt32> HandleCount;
- // If not null, points to our created device instance. Modified during lock only.
- DeviceBase* pDevice;
- // True if device is marked as available during enumeration.
- bool Enumerated;
-};
-
-
-
-// Common data present in the implementation of every DeviceBase.
-// Injected by DeviceImpl.
-class DeviceCommon
-{
-public:
- AtomicInt<UInt32> RefCount;
- Ptr<DeviceCreateDesc> pCreateDesc;
- Ptr<DeviceBase> pParent;
- MessageHandlerRef HandlerRef;
-
- DeviceCommon(DeviceCreateDesc* createDesc, DeviceBase* device, DeviceBase* parent)
- : RefCount(1), pCreateDesc(createDesc), pParent(parent), HandlerRef(device)
- {
- }
-
- // Device reference counting delegates to Manager thread to actually kill devices.
- void DeviceAddRef();
- void DeviceRelease();
-
- Lock* GetLock() const { return pCreateDesc->GetLock(); }
-
- virtual bool Initialize(DeviceBase* parent) = 0;
- virtual void Shutdown() = 0;
-};
-
-
-//-------------------------------------------------------------------------------------
-// DeviceImpl address DeviceRecord implementation to a device base class B.
-// B must be derived form DeviceBase.
-
-template<class B>
-class DeviceImpl : public B, public DeviceCommon
-{
-public:
- DeviceImpl(DeviceCreateDesc* createDesc, DeviceBase* parent)
- : DeviceCommon(createDesc, getThis(), parent)
- {
- }
-
- // Convenience method to avoid manager access typecasts.
- DeviceManagerImpl* GetManagerImpl() const { return pCreateDesc->pLock->pManager; }
-
- // Inline to avoid warnings.
- DeviceImpl* getThis() { return this; }
-
- // Common implementation delegate to avoid virtual inheritance and dynamic casts.
- virtual DeviceCommon* getDeviceCommon() const { return (DeviceCommon*)this; }
-
- /*
- virtual void AddRef() { pCreateDesc->DeviceAddRef(); }
- virtual void Release() { pCreateDesc->DeviceRelease(); }
- virtual DeviceBase* GetParent() const { return pParent.GetPtr(); }
- virtual DeviceManager* GetManager() const { return pCreateDesc->pLock->pManager;}
- virtual void SetMessageHandler(MessageHandler* handler) { HanderRef.SetHandler(handler); }
- virtual MessageHandler* GetMessageHandler() const { return HanderRef.GetHandler(); }
- virtual DeviceType GetType() const { return pCreateDesc->Type; }
- virtual DeviceType GetType() const { return pCreateDesc->Type; }
- */
-};
-
-
-//-------------------------------------------------------------------------------------
-// ***** DeviceFactory
-
-// DeviceFactory is maintained in DeviceManager for each separately-enumerable
-// device type; factories allow separation of unrelated enumeration code.
-
-class DeviceFactory : public ListNode<DeviceFactory>, public NewOverrideBase
-{
-public:
-
- DeviceFactory() : pManager(0)
- {
- pNext = pPrev = 0;
- }
- virtual ~DeviceFactory() { }
-
- DeviceManagerImpl* GetManagerImpl() { return pManager; }
-
- // Notifiers called when we are added to/removed from a device.
- virtual bool AddedToManager(DeviceManagerImpl* manager)
- {
- OVR_ASSERT(pManager == 0);
- pManager = manager;
- return true;
- }
-
- virtual void RemovedFromManager()
- {
- pManager = 0;
- }
-
-
- // *** Device Enumeration/Creation Support
-
- // Passed to EnumerateDevices to be informed of every device detected.
- class EnumerateVisitor
- {
- public:
- virtual void Visit(const DeviceCreateDesc& createDesc) = 0;
- };
-
- // Enumerates factory devices by notifying EnumerateVisitor about every
- // device that is present.
- virtual void EnumerateDevices(EnumerateVisitor& visitor) = 0;
-
- // Matches vendorId/productId pair with the factory; returns 'true'
- // if the factory can handle the device.
- virtual bool MatchVendorProduct(UInt16 vendorId, UInt16 productId) const
- {
- OVR_UNUSED2(vendorId, productId);
- return false;
- }
-
- // Detects the HID device and adds the DeviceCreateDesc into Devices list, if
- // the device belongs to this factory. Returns 'false', if not.
- virtual bool DetectHIDDevice(DeviceManager* pdevMgr, const HIDDeviceDesc& desc)
- {
- OVR_UNUSED2(pdevMgr, desc);
- return false;
- }
-
-protected:
- DeviceManagerImpl* pManager;
-};
-
-
-//-------------------------------------------------------------------------------------
-// ***** DeviceManagerImpl
-
-// DeviceManagerImpl is a partial default DeviceManager implementation that
-// maintains a list of devices and supports their enumeration.
-
-class DeviceManagerImpl : public DeviceImpl<OVR::DeviceManager>, public ThreadCommandQueue
-{
-public:
- DeviceManagerImpl();
- ~DeviceManagerImpl();
-
- // Constructor helper function to create Descriptor and manager lock during initialization.
- static DeviceCreateDesc* CreateManagerDesc();
-
- // DeviceManagerImpl provides partial implementation of Initialize/Shutdown that must
- // be called by the platform-specific derived class.
- virtual bool Initialize(DeviceBase* parent);
- virtual void Shutdown();
-
- // Override to return ThreadCommandQueue implementation used to post commands
- // to the background device manager thread (that must be created by Initialize).
- virtual ThreadCommandQueue* GetThreadQueue() = 0;
-
- // Returns the thread id of the DeviceManager.
- virtual ThreadId GetThreadId() const = 0;
-
- virtual DeviceEnumerator<> EnumerateDevicesEx(const DeviceEnumerationArgs& args);
-
-
- //
- void AddFactory(DeviceFactory* factory)
- {
- // This lock is only needed if we call AddFactory after manager thread creation.
- Lock::Locker scopeLock(GetLock());
- Factories.PushBack(factory);
- factory->AddedToManager(this);
- }
-
- void CallOnDeviceAdded(DeviceCreateDesc* desc)
- {
- HandlerRef.Call(MessageDeviceStatus(Message_DeviceAdded, this, DeviceHandle(desc)));
- }
- void CallOnDeviceRemoved(DeviceCreateDesc* desc)
- {
- HandlerRef.Call(MessageDeviceStatus(Message_DeviceRemoved, this, DeviceHandle(desc)));
- }
-
- // Helper to access Common data for a device.
- static DeviceCommon* GetDeviceCommon(DeviceBase* device)
- {
- return device->getDeviceCommon();
- }
-
-
- // Background-thread callbacks for DeviceCreation/Release. These
- DeviceBase* CreateDevice_MgrThread(DeviceCreateDesc* createDesc, DeviceBase* parent = 0);
- Void ReleaseDevice_MgrThread(DeviceBase* device);
-
-
- // Calls EnumerateDevices() on all factories
- virtual Void EnumerateAllFactoryDevices();
- // Enumerates devices for a particular factory.
- virtual Void EnumerateFactoryDevices(DeviceFactory* factory);
-
- virtual HIDDeviceManager* GetHIDDeviceManager() const
- {
- return HidDeviceManager;
- }
-
- // Adds device (DeviceCreateDesc*) into Devices. Returns NULL,
- // if unsuccessful or device is already in the list.
- virtual Ptr<DeviceCreateDesc> AddDevice_NeedsLock(const DeviceCreateDesc& createDesc);
-
- // Finds a device descriptor by path and optional type.
- Ptr<DeviceCreateDesc> FindDevice(const String& path, DeviceType = Device_None);
-
- // Finds HID device by HIDDeviceDesc.
- Ptr<DeviceCreateDesc> FindHIDDevice(const HIDDeviceDesc&);
- void DetectHIDDevice(const HIDDeviceDesc&);
-
- // Manager Lock-protected list of devices.
- List<DeviceCreateDesc> Devices;
-
- // Factories used to detect and manage devices.
- List<DeviceFactory> Factories;
-
-protected:
- Ptr<HIDDeviceManager> HidDeviceManager;
-};
-
-
-} // namespace OVR
-
-#endif
+/************************************************************************************
+
+Filename : OVR_DeviceImpl.h
+Content : Partial back-end independent implementation of Device interfaces
+Created : October 10, 2012
+Authors : Michael Antonov
+
+Copyright : Copyright 2012 Oculus VR, Inc. All Rights reserved.
+
+Use of this software is subject to the terms of the Oculus license
+agreement provided at the time of installation or download, or which
+otherwise accompanies this software in either electronic or hard copy form.
+
+*************************************************************************************/
+
+#ifndef OVR_DeviceImpl_h
+#define OVR_DeviceImpl_h
+
+#include "OVR_Device.h"
+#include "Kernel/OVR_Atomic.h"
+#include "Kernel/OVR_Log.h"
+#include "Kernel/OVR_System.h"
+
+#include "Kernel/OVR_Threads.h"
+#include "OVR_ThreadCommandQueue.h"
+#include "OVR_HIDDevice.h"
+
+namespace OVR {
+
+class DeviceManagerImpl;
+class DeviceFactory;
+
+enum
+{
+ Oculus_VendorId = 0x2833
+};
+
+//-------------------------------------------------------------------------------------
+// Globally shared Lock implementation used for MessageHandlers.
+
+class SharedLock
+{
+public:
+ SharedLock() : UseCount(0) {}
+
+ Lock* GetLockAddRef();
+ void ReleaseLock(Lock* plock);
+
+private:
+ Lock* toLock() { return (Lock*)Buffer; }
+
+ // UseCount and max alignment.
+ volatile int UseCount;
+ UInt64 Buffer[(sizeof(Lock)+sizeof(UInt64)-1)/sizeof(UInt64)];
+};
+
+
+// Wrapper for MessageHandler that includes synchronization logic.
+// References to MessageHandlers are organized in a list to allow for them to
+// easily removed with MessageHandler::RemoveAllHandlers.
+class MessageHandlerRef : public ListNode<MessageHandlerRef>
+{
+public:
+ MessageHandlerRef(DeviceBase* device);
+ ~MessageHandlerRef();
+
+ void SetHandler(MessageHandler* hander);
+
+ // Not-thread-safe version
+ void SetHandler_NTS(MessageHandler* hander);
+
+ void Call(const Message& msg)
+ {
+ Lock::Locker lockScope(pLock);
+ if (pHandler)
+ pHandler->OnMessage(msg);
+ }
+
+ Lock* GetLock() const { return pLock; }
+
+ // GetHandler() is not thread safe if used out of order across threads; nothing can be done
+ // about that.
+ MessageHandler* GetHandler() const { return pHandler; }
+ DeviceBase* GetDevice() const { return pDevice; }
+
+private:
+ Lock* pLock; // Cached global handler lock.
+ DeviceBase* pDevice;
+ MessageHandler* pHandler;
+};
+
+
+
+//-------------------------------------------------------------------------------------
+
+// DeviceManagerLock is a synchronization lock used by DeviceManager for Devices
+// and is allocated separately for potentially longer lifetime.
+//
+// DeviceManagerLock is used for all of the following:
+// - Adding/removing devices
+// - Reporting manager lifetime (pManager != 0) for DeviceHandles
+// - Protecting device creation/shutdown.
+
+class DeviceManagerLock : public RefCountBase<DeviceManagerLock>
+{
+public:
+ Lock CreateLock;
+ DeviceManagerImpl* pManager;
+
+ DeviceManagerLock() : pManager(0) { }
+};
+
+
+// DeviceCreateDesc provides all of the information needed to create any device, a derived
+// instance of this class is created by DeviceFactory during enumeration.
+// - DeviceCreateDesc may or may not be a part of DeviceManager::Devices list (check pNext != 0).
+// - Referenced and kept alive by DeviceHandle.
+
+class DeviceCreateDesc : public ListNode<DeviceCreateDesc>, public NewOverrideBase
+{
+ void operator = (const DeviceCreateDesc&) { } // Assign not supported; suppress MSVC warning.
+public:
+ DeviceCreateDesc(DeviceFactory* factory, DeviceType type)
+ : pFactory(factory), Type(type), pLock(0), HandleCount(0), pDevice(0), Enumerated(true)
+ {
+ pNext = pPrev = 0;
+ }
+
+ virtual ~DeviceCreateDesc()
+ {
+ OVR_ASSERT(!pDevice);
+ if (pNext)
+ RemoveNode();
+ }
+
+ DeviceManagerImpl* GetManagerImpl() const { return pLock->pManager; }
+ Lock* GetLock() const { return &pLock->CreateLock; }
+
+ // DeviceCreateDesc reference counting is tied to Devices list management,
+ // see comments for HandleCount.
+ void AddRef();
+ void Release();
+
+
+ // *** Device creation/matching Interface
+
+
+ // Cloning copies us to an allocated object when new device is enumerated.
+ virtual DeviceCreateDesc* Clone() const = 0;
+ // Creates a new device instance without Initializing it; the
+ // later is done my Initialize()/Shutdown() methods of the device itself.
+ virtual DeviceBase* NewDeviceInstance() = 0;
+ // Override to return device-specific info.
+ virtual bool GetDeviceInfo(DeviceInfo* info) const = 0;
+
+
+ enum MatchResult
+ {
+ Match_None,
+ Match_Found,
+ Match_Candidate
+ };
+
+ // Override to return Match_Found if descriptor matches our device.
+ // Match_Candidate can be returned, with pcandicate update, if this may be a match
+ // but more searching is necessary. If this is the case UpdateMatchedCandidate will be called.
+ virtual MatchResult MatchDevice(const DeviceCreateDesc& other,
+ DeviceCreateDesc** pcandidate) const = 0;
+
+ // Called for matched candidate after all potential matches are iterated.
+ // Used to update HMDevice creation arguments from Sensor.
+ // Optional return param 'newDeviceFlag' will be set to true if the
+ // 'desc' refers to a new device; false, otherwise.
+ // Return 'false' to create new object, 'true' if done with this argument.
+ virtual bool UpdateMatchedCandidate(
+ const DeviceCreateDesc& desc, bool* newDeviceFlag = NULL)
+ { OVR_UNUSED2(desc, newDeviceFlag); return false; }
+
+ // Matches HID device to the descriptor.
+ virtual bool MatchHIDDevice(const HIDDeviceDesc&) const { return false; }
+
+ // Matches device by path.
+ virtual bool MatchDevice(const String& /*path*/) { return false; }
+//protected:
+ DeviceFactory* const pFactory;
+ const DeviceType Type;
+
+ // List in which this descriptor lives. pList->CreateLock required if added/removed.
+ Ptr<DeviceManagerLock> pLock;
+
+ // Strong references to us: Incremented by Device, DeviceHandles & Enumerators.
+ // May be 0 if device not created and there are no handles.
+ // Following transitions require pList->CreateLock:
+ // {1 -> 0}: May delete & remove handle if no longer available.
+ // {0 -> 1}: Device creation is only possible if manager is still alive.
+ AtomicInt<UInt32> HandleCount;
+ // If not null, points to our created device instance. Modified during lock only.
+ DeviceBase* pDevice;
+ // True if device is marked as available during enumeration.
+ bool Enumerated;
+};
+
+
+
+// Common data present in the implementation of every DeviceBase.
+// Injected by DeviceImpl.
+class DeviceCommon
+{
+public:
+ AtomicInt<UInt32> RefCount;
+ Ptr<DeviceCreateDesc> pCreateDesc;
+ Ptr<DeviceBase> pParent;
+ MessageHandlerRef HandlerRef;
+
+ DeviceCommon(DeviceCreateDesc* createDesc, DeviceBase* device, DeviceBase* parent)
+ : RefCount(1), pCreateDesc(createDesc), pParent(parent), HandlerRef(device)
+ {
+ }
+
+ // Device reference counting delegates to Manager thread to actually kill devices.
+ void DeviceAddRef();
+ void DeviceRelease();
+
+ Lock* GetLock() const { return pCreateDesc->GetLock(); }
+
+ virtual bool Initialize(DeviceBase* parent) = 0;
+ virtual void Shutdown() = 0;
+};
+
+
+//-------------------------------------------------------------------------------------
+// DeviceImpl address DeviceRecord implementation to a device base class B.
+// B must be derived form DeviceBase.
+
+template<class B>
+class DeviceImpl : public B, public DeviceCommon
+{
+public:
+ DeviceImpl(DeviceCreateDesc* createDesc, DeviceBase* parent)
+ : DeviceCommon(createDesc, getThis(), parent)
+ {
+ }
+
+ // Convenience method to avoid manager access typecasts.
+ DeviceManagerImpl* GetManagerImpl() const { return pCreateDesc->pLock->pManager; }
+
+ // Inline to avoid warnings.
+ DeviceImpl* getThis() { return this; }
+
+ // Common implementation delegate to avoid virtual inheritance and dynamic casts.
+ virtual DeviceCommon* getDeviceCommon() const { return (DeviceCommon*)this; }
+
+ /*
+ virtual void AddRef() { pCreateDesc->DeviceAddRef(); }
+ virtual void Release() { pCreateDesc->DeviceRelease(); }
+ virtual DeviceBase* GetParent() const { return pParent.GetPtr(); }
+ virtual DeviceManager* GetManager() const { return pCreateDesc->pLock->pManager;}
+ virtual void SetMessageHandler(MessageHandler* handler) { HanderRef.SetHandler(handler); }
+ virtual MessageHandler* GetMessageHandler() const { return HanderRef.GetHandler(); }
+ virtual DeviceType GetType() const { return pCreateDesc->Type; }
+ virtual DeviceType GetType() const { return pCreateDesc->Type; }
+ */
+};
+
+
+//-------------------------------------------------------------------------------------
+// ***** DeviceFactory
+
+// DeviceFactory is maintained in DeviceManager for each separately-enumerable
+// device type; factories allow separation of unrelated enumeration code.
+
+class DeviceFactory : public ListNode<DeviceFactory>, public NewOverrideBase
+{
+public:
+
+ DeviceFactory() : pManager(0)
+ {
+ pNext = pPrev = 0;
+ }
+ virtual ~DeviceFactory() { }
+
+ DeviceManagerImpl* GetManagerImpl() { return pManager; }
+
+ // Notifiers called when we are added to/removed from a device.
+ virtual bool AddedToManager(DeviceManagerImpl* manager)
+ {
+ OVR_ASSERT(pManager == 0);
+ pManager = manager;
+ return true;
+ }
+
+ virtual void RemovedFromManager()
+ {
+ pManager = 0;
+ }
+
+
+ // *** Device Enumeration/Creation Support
+
+ // Passed to EnumerateDevices to be informed of every device detected.
+ class EnumerateVisitor
+ {
+ public:
+ virtual void Visit(const DeviceCreateDesc& createDesc) = 0;
+ };
+
+ // Enumerates factory devices by notifying EnumerateVisitor about every
+ // device that is present.
+ virtual void EnumerateDevices(EnumerateVisitor& visitor) = 0;
+
+ // Matches vendorId/productId pair with the factory; returns 'true'
+ // if the factory can handle the device.
+ virtual bool MatchVendorProduct(UInt16 vendorId, UInt16 productId) const
+ {
+ OVR_UNUSED2(vendorId, productId);
+ return false;
+ }
+
+ // Detects the HID device and adds the DeviceCreateDesc into Devices list, if
+ // the device belongs to this factory. Returns 'false', if not.
+ virtual bool DetectHIDDevice(DeviceManager* pdevMgr, const HIDDeviceDesc& desc)
+ {
+ OVR_UNUSED2(pdevMgr, desc);
+ return false;
+ }
+
+protected:
+ DeviceManagerImpl* pManager;
+};
+
+
+//-------------------------------------------------------------------------------------
+// ***** DeviceManagerImpl
+
+// DeviceManagerImpl is a partial default DeviceManager implementation that
+// maintains a list of devices and supports their enumeration.
+
+class DeviceManagerImpl : public DeviceImpl<OVR::DeviceManager>, public ThreadCommandQueue
+{
+public:
+ DeviceManagerImpl();
+ ~DeviceManagerImpl();
+
+ // Constructor helper function to create Descriptor and manager lock during initialization.
+ static DeviceCreateDesc* CreateManagerDesc();
+
+ // DeviceManagerImpl provides partial implementation of Initialize/Shutdown that must
+ // be called by the platform-specific derived class.
+ virtual bool Initialize(DeviceBase* parent);
+ virtual void Shutdown();
+
+
+ // Every DeviceManager has an associated profile manager, which us used to store
+ // user settings that may affect device behavior.
+ virtual ProfileManager* GetProfileManager() const { return pProfileManager.GetPtr(); }
+
+ // Override to return ThreadCommandQueue implementation used to post commands
+ // to the background device manager thread (that must be created by Initialize).
+ virtual ThreadCommandQueue* GetThreadQueue() = 0;
+
+ // Returns the thread id of the DeviceManager.
+ virtual ThreadId GetThreadId() const = 0;
+
+ virtual DeviceEnumerator<> EnumerateDevicesEx(const DeviceEnumerationArgs& args);
+
+
+ //
+ void AddFactory(DeviceFactory* factory)
+ {
+ // This lock is only needed if we call AddFactory after manager thread creation.
+ Lock::Locker scopeLock(GetLock());
+ Factories.PushBack(factory);
+ factory->AddedToManager(this);
+ }
+
+ void CallOnDeviceAdded(DeviceCreateDesc* desc)
+ {
+ HandlerRef.Call(MessageDeviceStatus(Message_DeviceAdded, this, DeviceHandle(desc)));
+ }
+ void CallOnDeviceRemoved(DeviceCreateDesc* desc)
+ {
+ HandlerRef.Call(MessageDeviceStatus(Message_DeviceRemoved, this, DeviceHandle(desc)));
+ }
+
+ // Helper to access Common data for a device.
+ static DeviceCommon* GetDeviceCommon(DeviceBase* device)
+ {
+ return device->getDeviceCommon();
+ }
+
+
+ // Background-thread callbacks for DeviceCreation/Release. These
+ DeviceBase* CreateDevice_MgrThread(DeviceCreateDesc* createDesc, DeviceBase* parent = 0);
+ Void ReleaseDevice_MgrThread(DeviceBase* device);
+
+
+ // Calls EnumerateDevices() on all factories
+ virtual Void EnumerateAllFactoryDevices();
+ // Enumerates devices for a particular factory.
+ virtual Void EnumerateFactoryDevices(DeviceFactory* factory);
+
+ virtual HIDDeviceManager* GetHIDDeviceManager() const
+ {
+ return HidDeviceManager;
+ }
+
+ // Adds device (DeviceCreateDesc*) into Devices. Returns NULL,
+ // if unsuccessful or device is already in the list.
+ virtual Ptr<DeviceCreateDesc> AddDevice_NeedsLock(const DeviceCreateDesc& createDesc);
+
+ // Finds a device descriptor by path and optional type.
+ Ptr<DeviceCreateDesc> FindDevice(const String& path, DeviceType = Device_None);
+
+ // Finds HID device by HIDDeviceDesc.
+ Ptr<DeviceCreateDesc> FindHIDDevice(const HIDDeviceDesc&);
+ void DetectHIDDevice(const HIDDeviceDesc&);
+
+ // Manager Lock-protected list of devices.
+ List<DeviceCreateDesc> Devices;
+
+ // Factories used to detect and manage devices.
+ List<DeviceFactory> Factories;
+
+protected:
+ Ptr<HIDDeviceManager> HidDeviceManager;
+ Ptr<ProfileManager> pProfileManager;
+};
+
+
+} // namespace OVR
+
+#endif
diff --git a/LibOVR/Src/OVR_DeviceMessages.h b/LibOVR/Src/OVR_DeviceMessages.h
index 97eb907..43f9496 100644
--- a/LibOVR/Src/OVR_DeviceMessages.h
+++ b/LibOVR/Src/OVR_DeviceMessages.h
@@ -1,162 +1,162 @@
-/************************************************************************************
-
-PublicHeader: OVR.h
-Filename : OVR_DeviceMessages.h
-Content : Definition of messages generated by devices
-Created : February 5, 2013
-Authors : Lee Cooper
-
-Copyright : Copyright 2013 Oculus VR, Inc. All Rights reserved.
-
-Use of this software is subject to the terms of the Oculus license
-agreement provided at the time of installation or download, or which
-otherwise accompanies this software in either electronic or hard copy form.
-
-*************************************************************************************/
-
-#ifndef OVR_DeviceMessages_h
-#define OVR_DeviceMessages_h
-
-#include "OVR_DeviceConstants.h"
-#include "OVR_DeviceHandle.h"
-
-#include "Kernel/OVR_Math.h"
-#include "Kernel/OVR_Array.h"
-#include "Kernel/OVR_Color.h"
-
-namespace OVR {
-
-class DeviceBase;
-class DeviceHandle;
-
-
-#define OVR_MESSAGETYPE(devName, msgIndex) ((Device_##devName << 8) | msgIndex)
-
-// MessageType identifies the structure of the Message class; based on the message,
-// casting can be used to obtain the exact value.
-enum MessageType
-{
- // Used for unassigned message types.
- Message_None = 0,
-
- // Device Manager Messages
- Message_DeviceAdded = OVR_MESSAGETYPE(Manager, 0), // A new device is detected by manager.
- Message_DeviceRemoved = OVR_MESSAGETYPE(Manager, 1), // Existing device has been plugged/unplugged.
- // Sensor Messages
- Message_BodyFrame = OVR_MESSAGETYPE(Sensor, 0), // Emitted by sensor at regular intervals.
- // Latency Tester Messages
- Message_LatencyTestSamples = OVR_MESSAGETYPE(LatencyTester, 0),
- Message_LatencyTestColorDetected = OVR_MESSAGETYPE(LatencyTester, 1),
- Message_LatencyTestStarted = OVR_MESSAGETYPE(LatencyTester, 2),
- Message_LatencyTestButton = OVR_MESSAGETYPE(LatencyTester, 3),
-
-};
-
-//-------------------------------------------------------------------------------------
-// Base class for all messages.
-class Message
-{
-public:
- Message(MessageType type = Message_None,
- DeviceBase* pdev = 0) : Type(type), pDevice(pdev)
- { }
-
- MessageType Type; // What kind of message this is.
- DeviceBase* pDevice; // Device that emitted the message.
-};
-
-
-// Sensor BodyFrame notification.
-// Sensor uses Right-Handed coordinate system to return results, with the following
-// axis definitions:
-// - Y Up positive
-// - X Right Positive
-// - Z Back Positive
-// Rotations a counter-clockwise (CCW) while looking in the negative direction
-// of the axis. This means they are interpreted as follows:
-// - Roll is rotation around Z, counter-clockwise (tilting left) in XY plane.
-// - Yaw is rotation around Y, positive for turning left.
-// - Pitch is rotation around X, positive for pitching up.
-
-class MessageBodyFrame : public Message
-{
-public:
- MessageBodyFrame(DeviceBase* dev)
- : Message(Message_BodyFrame, dev), Temperature(0.0f), TimeDelta(0.0f)
- {
- }
-
- Vector3f Acceleration; // Acceleration in m/s^2.
- Vector3f RotationRate; // Angular velocity in rad/s^2.
- Vector3f MagneticField; // Magnetic field strength in Gauss.
- float Temperature; // Temperature reading on sensor surface, in degrees Celsius.
- float TimeDelta; // Time passed since last Body Frame, in seconds.
-};
-
-// Sent when we receive a device status changes (e.g.:
-// Message_DeviceAdded, Message_DeviceRemoved).
-class MessageDeviceStatus : public Message
-{
-public:
- MessageDeviceStatus(MessageType type, DeviceBase* dev, const DeviceHandle &hdev)
- : Message(type, dev), Handle(hdev) { }
-
- DeviceHandle Handle;
-};
-
-//-------------------------------------------------------------------------------------
-// ***** Latency Tester
-
-// Sent when we receive Latency Tester samples.
-class MessageLatencyTestSamples : public Message
-{
-public:
- MessageLatencyTestSamples(DeviceBase* dev)
- : Message(Message_LatencyTestSamples, dev)
- {
- }
-
- Array<Color> Samples;
-};
-
-// Sent when a Latency Tester 'color detected' event occurs.
-class MessageLatencyTestColorDetected : public Message
-{
-public:
- MessageLatencyTestColorDetected(DeviceBase* dev)
- : Message(Message_LatencyTestColorDetected, dev)
- {
- }
-
- UInt16 Elapsed;
- Color DetectedValue;
- Color TargetValue;
-};
-
-// Sent when a Latency Tester 'change color' event occurs.
-class MessageLatencyTestStarted : public Message
-{
-public:
- MessageLatencyTestStarted(DeviceBase* dev)
- : Message(Message_LatencyTestStarted, dev)
- {
- }
-
- Color TargetValue;
-};
-
-// Sent when a Latency Tester 'button' event occurs.
-class MessageLatencyTestButton : public Message
-{
-public:
- MessageLatencyTestButton(DeviceBase* dev)
- : Message(Message_LatencyTestButton, dev)
- {
- }
-
-};
-
-
-} // namespace OVR
-
-#endif
+/************************************************************************************
+
+PublicHeader: OVR.h
+Filename : OVR_DeviceMessages.h
+Content : Definition of messages generated by devices
+Created : February 5, 2013
+Authors : Lee Cooper
+
+Copyright : Copyright 2013 Oculus VR, Inc. All Rights reserved.
+
+Use of this software is subject to the terms of the Oculus license
+agreement provided at the time of installation or download, or which
+otherwise accompanies this software in either electronic or hard copy form.
+
+*************************************************************************************/
+
+#ifndef OVR_DeviceMessages_h
+#define OVR_DeviceMessages_h
+
+#include "OVR_DeviceConstants.h"
+#include "OVR_DeviceHandle.h"
+
+#include "Kernel/OVR_Math.h"
+#include "Kernel/OVR_Array.h"
+#include "Kernel/OVR_Color.h"
+
+namespace OVR {
+
+class DeviceBase;
+class DeviceHandle;
+
+
+#define OVR_MESSAGETYPE(devName, msgIndex) ((Device_##devName << 8) | msgIndex)
+
+// MessageType identifies the structure of the Message class; based on the message,
+// casting can be used to obtain the exact value.
+enum MessageType
+{
+ // Used for unassigned message types.
+ Message_None = 0,
+
+ // Device Manager Messages
+ Message_DeviceAdded = OVR_MESSAGETYPE(Manager, 0), // A new device is detected by manager.
+ Message_DeviceRemoved = OVR_MESSAGETYPE(Manager, 1), // Existing device has been plugged/unplugged.
+ // Sensor Messages
+ Message_BodyFrame = OVR_MESSAGETYPE(Sensor, 0), // Emitted by sensor at regular intervals.
+ // Latency Tester Messages
+ Message_LatencyTestSamples = OVR_MESSAGETYPE(LatencyTester, 0),
+ Message_LatencyTestColorDetected = OVR_MESSAGETYPE(LatencyTester, 1),
+ Message_LatencyTestStarted = OVR_MESSAGETYPE(LatencyTester, 2),
+ Message_LatencyTestButton = OVR_MESSAGETYPE(LatencyTester, 3),
+
+};
+
+//-------------------------------------------------------------------------------------
+// Base class for all messages.
+class Message
+{
+public:
+ Message(MessageType type = Message_None,
+ DeviceBase* pdev = 0) : Type(type), pDevice(pdev)
+ { }
+
+ MessageType Type; // What kind of message this is.
+ DeviceBase* pDevice; // Device that emitted the message.
+};
+
+
+// Sensor BodyFrame notification.
+// Sensor uses Right-Handed coordinate system to return results, with the following
+// axis definitions:
+// - Y Up positive
+// - X Right Positive
+// - Z Back Positive
+// Rotations a counter-clockwise (CCW) while looking in the negative direction
+// of the axis. This means they are interpreted as follows:
+// - Roll is rotation around Z, counter-clockwise (tilting left) in XY plane.
+// - Yaw is rotation around Y, positive for turning left.
+// - Pitch is rotation around X, positive for pitching up.
+
+class MessageBodyFrame : public Message
+{
+public:
+ MessageBodyFrame(DeviceBase* dev)
+ : Message(Message_BodyFrame, dev), Temperature(0.0f), TimeDelta(0.0f)
+ {
+ }
+
+ Vector3f Acceleration; // Acceleration in m/s^2.
+ Vector3f RotationRate; // Angular velocity in rad/s^2.
+ Vector3f MagneticField; // Magnetic field strength in Gauss.
+ float Temperature; // Temperature reading on sensor surface, in degrees Celsius.
+ float TimeDelta; // Time passed since last Body Frame, in seconds.
+};
+
+// Sent when we receive a device status changes (e.g.:
+// Message_DeviceAdded, Message_DeviceRemoved).
+class MessageDeviceStatus : public Message
+{
+public:
+ MessageDeviceStatus(MessageType type, DeviceBase* dev, const DeviceHandle &hdev)
+ : Message(type, dev), Handle(hdev) { }
+
+ DeviceHandle Handle;
+};
+
+//-------------------------------------------------------------------------------------
+// ***** Latency Tester
+
+// Sent when we receive Latency Tester samples.
+class MessageLatencyTestSamples : public Message
+{
+public:
+ MessageLatencyTestSamples(DeviceBase* dev)
+ : Message(Message_LatencyTestSamples, dev)
+ {
+ }
+
+ Array<Color> Samples;
+};
+
+// Sent when a Latency Tester 'color detected' event occurs.
+class MessageLatencyTestColorDetected : public Message
+{
+public:
+ MessageLatencyTestColorDetected(DeviceBase* dev)
+ : Message(Message_LatencyTestColorDetected, dev)
+ {
+ }
+
+ UInt16 Elapsed;
+ Color DetectedValue;
+ Color TargetValue;
+};
+
+// Sent when a Latency Tester 'change color' event occurs.
+class MessageLatencyTestStarted : public Message
+{
+public:
+ MessageLatencyTestStarted(DeviceBase* dev)
+ : Message(Message_LatencyTestStarted, dev)
+ {
+ }
+
+ Color TargetValue;
+};
+
+// Sent when a Latency Tester 'button' event occurs.
+class MessageLatencyTestButton : public Message
+{
+public:
+ MessageLatencyTestButton(DeviceBase* dev)
+ : Message(Message_LatencyTestButton, dev)
+ {
+ }
+
+};
+
+
+} // namespace OVR
+
+#endif
diff --git a/LibOVR/Src/OVR_HIDDevice.h b/LibOVR/Src/OVR_HIDDevice.h
index b7ef089..512b96a 100644
--- a/LibOVR/Src/OVR_HIDDevice.h
+++ b/LibOVR/Src/OVR_HIDDevice.h
@@ -1,143 +1,143 @@
-/************************************************************************************
-
-Filename : OVR_HIDDevice.h
-Content : Cross platform HID device interface.
-Created : February 22, 2013
-Authors : Lee Cooper
-
-Copyright : Copyright 2013 Oculus VR, Inc. All Rights reserved.
-
-Use of this software is subject to the terms of the Oculus license
-agreement provided at the time of installation or download, or which
-otherwise accompanies this software in either electronic or hard copy form.
-
-*************************************************************************************/
-
-#ifndef OVR_HIDDevice_h
-#define OVR_HIDDevice_h
-
-#include "OVR_HIDDeviceBase.h"
-
-#include "Kernel/OVR_RefCount.h"
-#include "Kernel/OVR_String.h"
-#include "Kernel/OVR_Timer.h"
-
-namespace OVR {
-
-class HIDDevice;
-class DeviceManager;
-
-// HIDDeviceDesc contains interesting attributes of a HID device, including a Path
-// that can be used to create it.
-struct HIDDeviceDesc
-{
- UInt16 VendorId;
- UInt16 ProductId;
- UInt16 VersionNumber;
- UInt16 Usage;
- UInt16 UsagePage;
- String Path; // Platform specific.
- String Manufacturer;
- String Product;
- String SerialNumber;
-};
-
-// HIDEnumerateVisitor exposes a Visit interface called for every detected device
-// by HIDDeviceManager::Enumerate.
-class HIDEnumerateVisitor
-{
-public:
-
- // Should return true if we are interested in supporting
- // this HID VendorId and ProductId pair.
- virtual bool MatchVendorProduct(UInt16 vendorId, UInt16 productId)
- { OVR_UNUSED2(vendorId, productId); return true; }
-
- // Override to get notified about available device. Will only be called for
- // devices that matched MatchVendorProduct.
- virtual void Visit(HIDDevice&, const HIDDeviceDesc&) { }
-};
-
-
-//-------------------------------------------------------------------------------------
-// ***** HIDDeviceManager
-
-// Internal manager for enumerating and opening HID devices.
-// If an OVR::DeviceManager is created then an OVR::HIDDeviceManager will automatically be created and can be accessed from the
-// DeviceManager by calling 'GetHIDDeviceManager()'. When using HIDDeviceManager in standalone mode, the client must call
-// 'Create' below.
-class HIDDeviceManager : public RefCountBase<HIDDeviceManager>
-{
-public:
-
- // Creates a new HIDDeviceManager. Only one instance of HIDDeviceManager should be created at a time.
- static HIDDeviceManager* Create();
-
- // Enumerate HID devices using a HIDEnumerateVisitor derived visitor class.
- virtual bool Enumerate(HIDEnumerateVisitor* enumVisitor) = 0;
-
- // Open a HID device with the specified path.
- virtual HIDDevice* Open(const String& path) = 0;
-
-protected:
- HIDDeviceManager()
- { }
-};
-
-//-------------------------------------------------------------------------------------
-// ***** HIDDevice
-
-// HID device object. This is designed to be operated in synchronous
-// and asynchronous modes. With no handler set, input messages will be
-// stored and can be retrieved by calling 'Read' or 'ReadBlocking'.
-class HIDDevice : public RefCountBase<HIDDevice>, public HIDDeviceBase
-{
-public:
-
- HIDDevice()
- : Handler(NULL)
- {
- }
-
- virtual ~HIDDevice() {}
-
- virtual bool SetFeatureReport(UByte* data, UInt32 length) = 0;
- virtual bool GetFeatureReport(UByte* data, UInt32 length) = 0;
-
-// Not yet implemented.
-/*
- virtual bool Write(UByte* data, UInt32 length) = 0;
-
- virtual bool Read(UByte* pData, UInt32 length, UInt32 timeoutMilliS) = 0;
- virtual bool ReadBlocking(UByte* pData, UInt32 length) = 0;
-*/
-
- class HIDHandler
- {
- public:
- virtual void OnInputReport(UByte* pData, UInt32 length)
- { OVR_UNUSED2(pData, length); }
-
- virtual UInt64 OnTicks(UInt64 ticksMks)
- { OVR_UNUSED1(ticksMks); return Timer::MksPerSecond * 1000; ; }
-
- enum HIDDeviceMessageType
- {
- HIDDeviceMessage_DeviceAdded = 0,
- HIDDeviceMessage_DeviceRemoved = 1
- };
-
- virtual void OnDeviceMessage(HIDDeviceMessageType messageType)
- { OVR_UNUSED1(messageType); }
- };
-
- void SetHandler(HIDHandler* handler)
- { Handler = handler; }
-
-protected:
- HIDHandler* Handler;
-};
-
-} // namespace OVR
-
-#endif
+/************************************************************************************
+
+Filename : OVR_HIDDevice.h
+Content : Cross platform HID device interface.
+Created : February 22, 2013
+Authors : Lee Cooper
+
+Copyright : Copyright 2013 Oculus VR, Inc. All Rights reserved.
+
+Use of this software is subject to the terms of the Oculus license
+agreement provided at the time of installation or download, or which
+otherwise accompanies this software in either electronic or hard copy form.
+
+*************************************************************************************/
+
+#ifndef OVR_HIDDevice_h
+#define OVR_HIDDevice_h
+
+#include "OVR_HIDDeviceBase.h"
+
+#include "Kernel/OVR_RefCount.h"
+#include "Kernel/OVR_String.h"
+#include "Kernel/OVR_Timer.h"
+
+namespace OVR {
+
+class HIDDevice;
+class DeviceManager;
+
+// HIDDeviceDesc contains interesting attributes of a HID device, including a Path
+// that can be used to create it.
+struct HIDDeviceDesc
+{
+ UInt16 VendorId;
+ UInt16 ProductId;
+ UInt16 VersionNumber;
+ UInt16 Usage;
+ UInt16 UsagePage;
+ String Path; // Platform specific.
+ String Manufacturer;
+ String Product;
+ String SerialNumber;
+};
+
+// HIDEnumerateVisitor exposes a Visit interface called for every detected device
+// by HIDDeviceManager::Enumerate.
+class HIDEnumerateVisitor
+{
+public:
+
+ // Should return true if we are interested in supporting
+ // this HID VendorId and ProductId pair.
+ virtual bool MatchVendorProduct(UInt16 vendorId, UInt16 productId)
+ { OVR_UNUSED2(vendorId, productId); return true; }
+
+ // Override to get notified about available device. Will only be called for
+ // devices that matched MatchVendorProduct.
+ virtual void Visit(HIDDevice&, const HIDDeviceDesc&) { }
+};
+
+
+//-------------------------------------------------------------------------------------
+// ***** HIDDeviceManager
+
+// Internal manager for enumerating and opening HID devices.
+// If an OVR::DeviceManager is created then an OVR::HIDDeviceManager will automatically be created and can be accessed from the
+// DeviceManager by calling 'GetHIDDeviceManager()'. When using HIDDeviceManager in standalone mode, the client must call
+// 'Create' below.
+class HIDDeviceManager : public RefCountBase<HIDDeviceManager>
+{
+public:
+
+ // Creates a new HIDDeviceManager. Only one instance of HIDDeviceManager should be created at a time.
+ static HIDDeviceManager* Create();
+
+ // Enumerate HID devices using a HIDEnumerateVisitor derived visitor class.
+ virtual bool Enumerate(HIDEnumerateVisitor* enumVisitor) = 0;
+
+ // Open a HID device with the specified path.
+ virtual HIDDevice* Open(const String& path) = 0;
+
+protected:
+ HIDDeviceManager()
+ { }
+};
+
+//-------------------------------------------------------------------------------------
+// ***** HIDDevice
+
+// HID device object. This is designed to be operated in synchronous
+// and asynchronous modes. With no handler set, input messages will be
+// stored and can be retrieved by calling 'Read' or 'ReadBlocking'.
+class HIDDevice : public RefCountBase<HIDDevice>, public HIDDeviceBase
+{
+public:
+
+ HIDDevice()
+ : Handler(NULL)
+ {
+ }
+
+ virtual ~HIDDevice() {}
+
+ virtual bool SetFeatureReport(UByte* data, UInt32 length) = 0;
+ virtual bool GetFeatureReport(UByte* data, UInt32 length) = 0;
+
+// Not yet implemented.
+/*
+ virtual bool Write(UByte* data, UInt32 length) = 0;
+
+ virtual bool Read(UByte* pData, UInt32 length, UInt32 timeoutMilliS) = 0;
+ virtual bool ReadBlocking(UByte* pData, UInt32 length) = 0;
+*/
+
+ class HIDHandler
+ {
+ public:
+ virtual void OnInputReport(UByte* pData, UInt32 length)
+ { OVR_UNUSED2(pData, length); }
+
+ virtual UInt64 OnTicks(UInt64 ticksMks)
+ { OVR_UNUSED1(ticksMks); return Timer::MksPerSecond * 1000; ; }
+
+ enum HIDDeviceMessageType
+ {
+ HIDDeviceMessage_DeviceAdded = 0,
+ HIDDeviceMessage_DeviceRemoved = 1
+ };
+
+ virtual void OnDeviceMessage(HIDDeviceMessageType messageType)
+ { OVR_UNUSED1(messageType); }
+ };
+
+ void SetHandler(HIDHandler* handler)
+ { Handler = handler; }
+
+protected:
+ HIDHandler* Handler;
+};
+
+} // namespace OVR
+
+#endif
diff --git a/LibOVR/Src/OVR_HIDDeviceBase.h b/LibOVR/Src/OVR_HIDDeviceBase.h
index 42fdadc..4532b76 100644
--- a/LibOVR/Src/OVR_HIDDeviceBase.h
+++ b/LibOVR/Src/OVR_HIDDeviceBase.h
@@ -1,40 +1,40 @@
-/************************************************************************************
-
-PublicHeader: OVR.h
-Filename : OVR_HIDDeviceBase.h
-Content : Definition of HID device interface.
-Created : March 11, 2013
-Authors : Lee Cooper
-
-Copyright : Copyright 2013 Oculus VR, Inc. All Rights reserved.
-
-Use of this software is subject to the terms of the Oculus license
-agreement provided at the time of installation or download, or which
-otherwise accompanies this software in either electronic or hard copy form.
-
-*************************************************************************************/
-
-#ifndef OVR_HIDDeviceBase_h
-#define OVR_HIDDeviceBase_h
-
-#include "Kernel/OVR_Types.h"
-
-namespace OVR {
-
-//-------------------------------------------------------------------------------------
-// ***** HIDDeviceBase
-
-// Base interface for HID devices.
-class HIDDeviceBase
-{
-public:
-
- virtual ~HIDDeviceBase() { }
-
- virtual bool SetFeatureReport(UByte* data, UInt32 length) = 0;
- virtual bool GetFeatureReport(UByte* data, UInt32 length) = 0;
-};
-
-} // namespace OVR
-
-#endif
+/************************************************************************************
+
+PublicHeader: OVR.h
+Filename : OVR_HIDDeviceBase.h
+Content : Definition of HID device interface.
+Created : March 11, 2013
+Authors : Lee Cooper
+
+Copyright : Copyright 2013 Oculus VR, Inc. All Rights reserved.
+
+Use of this software is subject to the terms of the Oculus license
+agreement provided at the time of installation or download, or which
+otherwise accompanies this software in either electronic or hard copy form.
+
+*************************************************************************************/
+
+#ifndef OVR_HIDDeviceBase_h
+#define OVR_HIDDeviceBase_h
+
+#include "Kernel/OVR_Types.h"
+
+namespace OVR {
+
+//-------------------------------------------------------------------------------------
+// ***** HIDDeviceBase
+
+// Base interface for HID devices.
+class HIDDeviceBase
+{
+public:
+
+ virtual ~HIDDeviceBase() { }
+
+ virtual bool SetFeatureReport(UByte* data, UInt32 length) = 0;
+ virtual bool GetFeatureReport(UByte* data, UInt32 length) = 0;
+};
+
+} // namespace OVR
+
+#endif
diff --git a/LibOVR/Src/OVR_HIDDeviceImpl.h b/LibOVR/Src/OVR_HIDDeviceImpl.h
index c5163b4..f9d0922 100644
--- a/LibOVR/Src/OVR_HIDDeviceImpl.h
+++ b/LibOVR/Src/OVR_HIDDeviceImpl.h
@@ -1,203 +1,203 @@
-/************************************************************************************
-
-Filename : OVR_HIDDeviceImpl.h
-Content : Implementation of HIDDevice.
-Created : March 7, 2013
-Authors : Lee Cooper
-
-Copyright : Copyright 2013 Oculus VR, Inc. All Rights reserved.
-
-Use of this software is subject to the terms of the Oculus license
-agreement provided at the time of installation or download, or which
-otherwise accompanies this software in either electronic or hard copy form.
-
-*************************************************************************************/
-
-#ifndef OVR_HIDDeviceImpl_h
-#define OVR_HIDDeviceImpl_h
-
-//#include "OVR_Device.h"
-#include "OVR_DeviceImpl.h"
-
-namespace OVR {
-
-//-------------------------------------------------------------------------------------
-class HIDDeviceCreateDesc : public DeviceCreateDesc
-{
-public:
- HIDDeviceCreateDesc(DeviceFactory* factory, DeviceType type, const HIDDeviceDesc& hidDesc)
- : DeviceCreateDesc(factory, type), HIDDesc(hidDesc) { }
- HIDDeviceCreateDesc(const HIDDeviceCreateDesc& other)
- : DeviceCreateDesc(other.pFactory, other.Type), HIDDesc(other.HIDDesc) { }
-
- virtual bool MatchDevice(const String& path)
- {
- // should it be case insensitive?
- return HIDDesc.Path.CompareNoCase(path) == 0;
- }
-
- HIDDeviceDesc HIDDesc;
-};
-
-//-------------------------------------------------------------------------------------
-template<class B>
-class HIDDeviceImpl : public DeviceImpl<B>, public HIDDevice::HIDHandler
-{
-public:
- HIDDeviceImpl(HIDDeviceCreateDesc* createDesc, DeviceBase* parent)
- : DeviceImpl<B>(createDesc, parent)
- {
- }
-
- // HIDDevice::Handler interface.
- virtual void OnDeviceMessage(HIDDeviceMessageType messageType)
- {
- MessageType handlerMessageType;
- switch (messageType) {
- case HIDDeviceMessage_DeviceAdded:
- handlerMessageType = Message_DeviceAdded;
- break;
-
- case HIDDeviceMessage_DeviceRemoved:
- handlerMessageType = Message_DeviceRemoved;
- break;
-
- default: OVR_ASSERT(0); return;
- }
-
- // Do device notification.
- {
- Lock::Locker scopeLock(this->HandlerRef.GetLock());
-
- if (this->HandlerRef.GetHandler())
- {
- MessageDeviceStatus status(handlerMessageType, this, OVR::DeviceHandle(this->pCreateDesc));
- this->HandlerRef.GetHandler()->OnMessage(status);
- }
- }
-
- // Do device manager notification.
- DeviceManagerImpl* manager = this->GetManagerImpl();
- switch (handlerMessageType) {
- case Message_DeviceAdded:
- manager->CallOnDeviceAdded(this->pCreateDesc);
- break;
-
- case Message_DeviceRemoved:
- manager->CallOnDeviceRemoved(this->pCreateDesc);
- break;
-
- default:;
- }
- }
-
- virtual bool Initialize(DeviceBase* parent)
- {
- // Open HID device.
- HIDDeviceDesc& hidDesc = *getHIDDesc();
- HIDDeviceManager* pManager = GetHIDDeviceManager();
-
-
- HIDDevice* device = pManager->Open(hidDesc.Path);
- if (!device)
- {
- return false;
- }
-
- InternalDevice = *device;
- InternalDevice->SetHandler(this);
-
- // AddRef() to parent, forcing chain to stay alive.
- DeviceImpl<B>::pParent = parent;
-
- return true;
- }
-
- virtual void Shutdown()
- {
- InternalDevice->SetHandler(NULL);
-
- // Remove the handler, if any.
- this->HandlerRef.SetHandler(0);
-
- DeviceImpl<B>::pParent.Clear();
- }
-
- DeviceManager* GetDeviceManager()
- {
- return DeviceImpl<B>::pCreateDesc->GetManagerImpl();
- }
-
- HIDDeviceManager* GetHIDDeviceManager()
- {
- return DeviceImpl<B>::pCreateDesc->GetManagerImpl()->GetHIDDeviceManager();
- }
-
-
- struct WriteData
- {
- enum { BufferSize = 64 };
- UByte Buffer[64];
- UPInt Size;
-
- WriteData(UByte* data, UPInt size) : Size(size)
- {
- OVR_ASSERT(size <= BufferSize);
- memcpy(Buffer, data, size);
- }
- };
-
- bool SetFeatureReport(UByte* data, UInt32 length)
- {
- WriteData writeData(data, length);
-
- // Push call with wait.
- bool result = false;
-
- ThreadCommandQueue* pQueue = this->GetManagerImpl()->GetThreadQueue();
- if (!pQueue->PushCallAndWaitResult(this, &HIDDeviceImpl::setFeatureReport, &result, writeData))
- return false;
-
- return result;
- }
-
- bool setFeatureReport(const WriteData& data)
- {
- return InternalDevice->SetFeatureReport((UByte*) data.Buffer, (UInt32) data.Size);
- }
-
- bool GetFeatureReport(UByte* data, UInt32 length)
- {
- bool result = false;
-
- ThreadCommandQueue* pQueue = this->GetManagerImpl()->GetThreadQueue();
- if (!pQueue->PushCallAndWaitResult(this, &HIDDeviceImpl::getFeatureReport, &result, data, length))
- return false;
-
- return result;
- }
-
- bool getFeatureReport(UByte* data, UInt32 length)
- {
- return InternalDevice->GetFeatureReport(data, length);
- }
-
-protected:
- HIDDevice* GetInternalDevice() const
- {
- return InternalDevice;
- }
-
- HIDDeviceDesc* getHIDDesc() const
- { return &getCreateDesc()->HIDDesc; }
-
- HIDDeviceCreateDesc* getCreateDesc() const
- { return (HIDDeviceCreateDesc*) &(*DeviceImpl<B>::pCreateDesc); }
-
-private:
- Ptr<HIDDevice> InternalDevice;
-};
-
-} // namespace OVR
-
-#endif
+/************************************************************************************
+
+Filename : OVR_HIDDeviceImpl.h
+Content : Implementation of HIDDevice.
+Created : March 7, 2013
+Authors : Lee Cooper
+
+Copyright : Copyright 2013 Oculus VR, Inc. All Rights reserved.
+
+Use of this software is subject to the terms of the Oculus license
+agreement provided at the time of installation or download, or which
+otherwise accompanies this software in either electronic or hard copy form.
+
+*************************************************************************************/
+
+#ifndef OVR_HIDDeviceImpl_h
+#define OVR_HIDDeviceImpl_h
+
+//#include "OVR_Device.h"
+#include "OVR_DeviceImpl.h"
+
+namespace OVR {
+
+//-------------------------------------------------------------------------------------
+class HIDDeviceCreateDesc : public DeviceCreateDesc
+{
+public:
+ HIDDeviceCreateDesc(DeviceFactory* factory, DeviceType type, const HIDDeviceDesc& hidDesc)
+ : DeviceCreateDesc(factory, type), HIDDesc(hidDesc) { }
+ HIDDeviceCreateDesc(const HIDDeviceCreateDesc& other)
+ : DeviceCreateDesc(other.pFactory, other.Type), HIDDesc(other.HIDDesc) { }
+
+ virtual bool MatchDevice(const String& path)
+ {
+ // should it be case insensitive?
+ return HIDDesc.Path.CompareNoCase(path) == 0;
+ }
+
+ HIDDeviceDesc HIDDesc;
+};
+
+//-------------------------------------------------------------------------------------
+template<class B>
+class HIDDeviceImpl : public DeviceImpl<B>, public HIDDevice::HIDHandler
+{
+public:
+ HIDDeviceImpl(HIDDeviceCreateDesc* createDesc, DeviceBase* parent)
+ : DeviceImpl<B>(createDesc, parent)
+ {
+ }
+
+ // HIDDevice::Handler interface.
+ virtual void OnDeviceMessage(HIDDeviceMessageType messageType)
+ {
+ MessageType handlerMessageType;
+ switch (messageType) {
+ case HIDDeviceMessage_DeviceAdded:
+ handlerMessageType = Message_DeviceAdded;
+ break;
+
+ case HIDDeviceMessage_DeviceRemoved:
+ handlerMessageType = Message_DeviceRemoved;
+ break;
+
+ default: OVR_ASSERT(0); return;
+ }
+
+ // Do device notification.
+ {
+ Lock::Locker scopeLock(this->HandlerRef.GetLock());
+
+ if (this->HandlerRef.GetHandler())
+ {
+ MessageDeviceStatus status(handlerMessageType, this, OVR::DeviceHandle(this->pCreateDesc));
+ this->HandlerRef.GetHandler()->OnMessage(status);
+ }
+ }
+
+ // Do device manager notification.
+ DeviceManagerImpl* manager = this->GetManagerImpl();
+ switch (handlerMessageType) {
+ case Message_DeviceAdded:
+ manager->CallOnDeviceAdded(this->pCreateDesc);
+ break;
+
+ case Message_DeviceRemoved:
+ manager->CallOnDeviceRemoved(this->pCreateDesc);
+ break;
+
+ default:;
+ }
+ }
+
+ virtual bool Initialize(DeviceBase* parent)
+ {
+ // Open HID device.
+ HIDDeviceDesc& hidDesc = *getHIDDesc();
+ HIDDeviceManager* pManager = GetHIDDeviceManager();
+
+
+ HIDDevice* device = pManager->Open(hidDesc.Path);
+ if (!device)
+ {
+ return false;
+ }
+
+ InternalDevice = *device;
+ InternalDevice->SetHandler(this);
+
+ // AddRef() to parent, forcing chain to stay alive.
+ DeviceImpl<B>::pParent = parent;
+
+ return true;
+ }
+
+ virtual void Shutdown()
+ {
+ InternalDevice->SetHandler(NULL);
+
+ // Remove the handler, if any.
+ this->HandlerRef.SetHandler(0);
+
+ DeviceImpl<B>::pParent.Clear();
+ }
+
+ DeviceManager* GetDeviceManager()
+ {
+ return DeviceImpl<B>::pCreateDesc->GetManagerImpl();
+ }
+
+ HIDDeviceManager* GetHIDDeviceManager()
+ {
+ return DeviceImpl<B>::pCreateDesc->GetManagerImpl()->GetHIDDeviceManager();
+ }
+
+
+ struct WriteData
+ {
+ enum { BufferSize = 64 };
+ UByte Buffer[64];
+ UPInt Size;
+
+ WriteData(UByte* data, UPInt size) : Size(size)
+ {
+ OVR_ASSERT(size <= BufferSize);
+ memcpy(Buffer, data, size);
+ }
+ };
+
+ bool SetFeatureReport(UByte* data, UInt32 length)
+ {
+ WriteData writeData(data, length);
+
+ // Push call with wait.
+ bool result = false;
+
+ ThreadCommandQueue* pQueue = this->GetManagerImpl()->GetThreadQueue();
+ if (!pQueue->PushCallAndWaitResult(this, &HIDDeviceImpl::setFeatureReport, &result, writeData))
+ return false;
+
+ return result;
+ }
+
+ bool setFeatureReport(const WriteData& data)
+ {
+ return InternalDevice->SetFeatureReport((UByte*) data.Buffer, (UInt32) data.Size);
+ }
+
+ bool GetFeatureReport(UByte* data, UInt32 length)
+ {
+ bool result = false;
+
+ ThreadCommandQueue* pQueue = this->GetManagerImpl()->GetThreadQueue();
+ if (!pQueue->PushCallAndWaitResult(this, &HIDDeviceImpl::getFeatureReport, &result, data, length))
+ return false;
+
+ return result;
+ }
+
+ bool getFeatureReport(UByte* data, UInt32 length)
+ {
+ return InternalDevice->GetFeatureReport(data, length);
+ }
+
+protected:
+ HIDDevice* GetInternalDevice() const
+ {
+ return InternalDevice;
+ }
+
+ HIDDeviceDesc* getHIDDesc() const
+ { return &getCreateDesc()->HIDDesc; }
+
+ HIDDeviceCreateDesc* getCreateDesc() const
+ { return (HIDDeviceCreateDesc*) &(*DeviceImpl<B>::pCreateDesc); }
+
+private:
+ Ptr<HIDDevice> InternalDevice;
+};
+
+} // namespace OVR
+
+#endif
diff --git a/LibOVR/Src/OVR_JSON.cpp b/LibOVR/Src/OVR_JSON.cpp
new file mode 100644
index 0000000..eb54b04
--- /dev/null
+++ b/LibOVR/Src/OVR_JSON.cpp
@@ -0,0 +1,1056 @@
+/************************************************************************************
+
+PublicHeader: None
+Filename : OVR_JSON.h
+Content : JSON format reader and writer
+Created : April 9, 2013
+Author : Brant Lewis
+Notes :
+ The code is a derivative of the cJSON library written by Dave Gamble and subject
+ to the following permissive copyright.
+
+ Copyright (c) 2009 Dave Gamble
+
+ 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.
+
+
+Copyright : Copyright 2012 Oculus VR, Inc. All Rights reserved.
+
+Use of this software is subject to the terms of the Oculus license
+agreement provided at the time of installation or download, or which
+otherwise accompanies this software in either electronic or hard copy form.
+
+************************************************************************************/
+
+#include <string.h>
+#include <stdio.h>
+#include <math.h>
+#include <stdlib.h>
+#include <float.h>
+#include <limits.h>
+#include <ctype.h>
+#include "OVR_JSON.h"
+#include "Kernel/OVR_SysFile.h"
+#include "Kernel/OVR_Log.h"
+
+namespace OVR {
+
+
+//-----------------------------------------------------------------------------
+// Create a new copy of a string
+static char* JSON_strdup(const char* str)
+{
+ UPInt len = OVR_strlen(str) + 1;
+ char* copy = (char*)OVR_ALLOC(len);
+ if (!copy)
+ return 0;
+ memcpy(copy, str, len);
+ return copy;
+}
+
+
+//-----------------------------------------------------------------------------
+// Render the number from the given item into a string.
+static char* PrintNumber(double d)
+{
+ char *str;
+ //double d=item->valuedouble;
+ int valueint = (int)d;
+ if (fabs(((double)valueint)-d)<=DBL_EPSILON && d<=INT_MAX && d>=INT_MIN)
+ {
+ str=(char*)OVR_ALLOC(21); // 2^64+1 can be represented in 21 chars.
+ if (str)
+ OVR_sprintf(str, 21, "%d", valueint);
+ }
+ else
+ {
+ str=(char*)OVR_ALLOC(64); // This is a nice tradeoff.
+ if (str)
+ {
+ if (fabs(floor(d)-d)<=DBL_EPSILON && fabs(d)<1.0e60)
+ OVR_sprintf(str, 64, "%.0f", d);
+ else if (fabs(d)<1.0e-6 || fabs(d)>1.0e9)
+ OVR_sprintf(str, 64, "%e", d);
+ else
+ OVR_sprintf(str, 64, "%f", d);
+ }
+ }
+ return str;
+}
+
+// Parse the input text into an un-escaped cstring, and populate item.
+static const unsigned char firstByteMark[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC };
+
+// Helper to assign error sting and return 0.
+const char* AssignError(const char** perror, const char *errorMessage)
+{
+ if (perror)
+ *perror = errorMessage;
+ return 0;
+}
+
+//-----------------------------------------------------------------------------
+// ***** JSON Node class
+
+JSON::JSON(JSONItemType itemType)
+ : Type(itemType), dValue(0.0)
+{
+}
+
+JSON::~JSON()
+{
+ JSON* child = Children.GetFirst();
+ while (!Children.IsNull(child))
+ {
+ child->RemoveNode();
+ child->Release();
+ child = Children.GetFirst();
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Parse the input text to generate a number, and populate the result into item
+// Returns the text position after the parsed number
+const char* JSON::parseNumber(const char *num)
+{
+ const char* num_start = num;
+ double n=0, sign=1, scale=0;
+ int subscale = 0,
+ signsubscale = 1;
+
+ // Could use sscanf for this?
+ if (*num=='-')
+ sign=-1,num++; // Has sign?
+ if (*num=='0')
+ num++; // is zero
+
+ if (*num>='1' && *num<='9')
+ {
+ do
+ {
+ n=(n*10.0)+(*num++ -'0');
+ }
+ while (*num>='0' && *num<='9'); // Number?
+ }
+
+ if (*num=='.' && num[1]>='0' && num[1]<='9')
+ {
+ num++;
+ do
+ {
+ n=(n*10.0)+(*num++ -'0');
+ scale--;
+ }
+ while (*num>='0' && *num<='9'); // Fractional part?
+ }
+
+ if (*num=='e' || *num=='E') // Exponent?
+ {
+ num++;
+ if (*num=='+')
+ num++;
+ else if (*num=='-')
+ {
+ signsubscale=-1;
+ num++; // With sign?
+ }
+
+ while (*num>='0' && *num<='9')
+ subscale=(subscale*10)+(*num++ - '0'); // Number?
+ }
+
+ // Number = +/- number.fraction * 10^+/- exponent
+ n = sign*n*pow(10.0,(scale+subscale*signsubscale));
+
+ // Assign parsed value.
+ Type = JSON_Number;
+ dValue = n;
+ Value.AssignString(num_start, num - num_start);
+
+ return num;
+}
+
+// Parses a hex string up to the specified number of digits.
+// Returns the first character after the string.
+const char* ParseHex(unsigned* val, unsigned digits, const char* str)
+{
+ *val = 0;
+
+ for(unsigned digitCount = 0; digitCount < digits; digitCount++, str++)
+ {
+ unsigned v = *str;
+
+ if ((v >= '0') && (v <= '9'))
+ v -= '0';
+ else if ((v >= 'a') && (v <= 'f'))
+ v = 10 + v - 'a';
+ else if ((v >= 'A') && (v <= 'F'))
+ v = 10 + v - 'A';
+ else
+ break;
+
+ *val = *val * 16 + v;
+ }
+
+ return str;
+}
+
+//-----------------------------------------------------------------------------
+// Parses the input text into a string item and returns the text position after
+// the parsed string
+const char* JSON::parseString(const char* str, const char** perror)
+{
+ const char* ptr = str+1;
+ const char* p;
+ char* ptr2;
+ char* out;
+ int len=0;
+ unsigned uc, uc2;
+
+ if (*str!='\"')
+ {
+ return AssignError(perror, "Syntax Error: Missing quote");
+ }
+
+ while (*ptr!='\"' && *ptr && ++len)
+ {
+ if (*ptr++ == '\\') ptr++; // Skip escaped quotes.
+ }
+
+ // This is how long we need for the string, roughly.
+ out=(char*)OVR_ALLOC(len+1);
+ if (!out)
+ return 0;
+
+ ptr = str+1;
+ ptr2= out;
+
+ while (*ptr!='\"' && *ptr)
+ {
+ if (*ptr!='\\')
+ {
+ *ptr2++ = *ptr++;
+ }
+ else
+ {
+ ptr++;
+ switch (*ptr)
+ {
+ case 'b': *ptr2++ = '\b'; break;
+ case 'f': *ptr2++ = '\f'; break;
+ case 'n': *ptr2++ = '\n'; break;
+ case 'r': *ptr2++ = '\r'; break;
+ case 't': *ptr2++ = '\t'; break;
+
+ // Transcode utf16 to utf8.
+ case 'u':
+
+ // Get the unicode char.
+ p = ParseHex(&uc, 4, ptr + 1);
+ if (ptr != p)
+ ptr = p - 1;
+
+ if ((uc>=0xDC00 && uc<=0xDFFF) || uc==0)
+ break; // Check for invalid.
+
+ // UTF16 surrogate pairs.
+ if (uc>=0xD800 && uc<=0xDBFF)
+ {
+ if (ptr[1]!='\\' || ptr[2]!='u')
+ break; // Missing second-half of surrogate.
+
+ p= ParseHex(&uc2, 4, ptr + 3);
+ if (ptr != p)
+ ptr = p - 1;
+
+ if (uc2<0xDC00 || uc2>0xDFFF)
+ break; // Invalid second-half of surrogate.
+
+ uc = 0x10000 + (((uc&0x3FF)<<10) | (uc2&0x3FF));
+ }
+
+ len=4;
+
+ if (uc<0x80)
+ len=1;
+ else if (uc<0x800)
+ len=2;
+ else if (uc<0x10000)
+ len=3;
+
+ ptr2+=len;
+
+ switch (len)
+ {
+ case 4: *--ptr2 =((uc | 0x80) & 0xBF); uc >>= 6;
+ case 3: *--ptr2 =((uc | 0x80) & 0xBF); uc >>= 6;
+ case 2: *--ptr2 =((uc | 0x80) & 0xBF); uc >>= 6;
+ case 1: *--ptr2 = (char)(uc | firstByteMark[len]);
+ }
+ ptr2+=len;
+ break;
+
+ default:
+ *ptr2++ = *ptr;
+ break;
+ }
+ ptr++;
+ }
+ }
+
+ *ptr2 = 0;
+ if (*ptr=='\"')
+ ptr++;
+
+ // Make a copy of the string
+ Value=out;
+ OVR_FREE(out);
+ Type=JSON_String;
+
+ return ptr;
+}
+
+//-----------------------------------------------------------------------------
+// Render the string provided to an escaped version that can be printed.
+char* PrintString(const char* str)
+{
+ const char *ptr;
+ char *ptr2,*out;
+ int len=0;
+ unsigned char token;
+
+ if (!str)
+ return JSON_strdup("");
+ ptr=str;
+
+ token=*ptr;
+ while (token && ++len)\
+ {
+ if (strchr("\"\\\b\f\n\r\t",token))
+ len++;
+ else if (token<32)
+ len+=5;
+ ptr++;
+ token=*ptr;
+ }
+
+ int buff_size = len+3;
+ out=(char*)OVR_ALLOC(buff_size);
+ if (!out)
+ return 0;
+
+ ptr2 = out;
+ ptr = str;
+ *ptr2++ = '\"';
+
+ while (*ptr)
+ {
+ if ((unsigned char)*ptr>31 && *ptr!='\"' && *ptr!='\\')
+ *ptr2++=*ptr++;
+ else
+ {
+ *ptr2++='\\';
+ switch (token=*ptr++)
+ {
+ case '\\': *ptr2++='\\'; break;
+ case '\"': *ptr2++='\"'; break;
+ case '\b': *ptr2++='b'; break;
+ case '\f': *ptr2++='f'; break;
+ case '\n': *ptr2++='n'; break;
+ case '\r': *ptr2++='r'; break;
+ case '\t': *ptr2++='t'; break;
+ default:
+ OVR_sprintf(ptr2, buff_size - (ptr2-out), "u%04x",token);
+ ptr2+=5;
+ break; // Escape and print.
+ }
+ }
+ }
+ *ptr2++='\"';
+ *ptr2++=0;
+ return out;
+}
+
+//-----------------------------------------------------------------------------
+// Utility to jump whitespace and cr/lf
+static const char* skip(const char* in)
+{
+ while (in && *in && (unsigned char)*in<=' ')
+ in++;
+ return in;
+}
+
+//-----------------------------------------------------------------------------
+// Parses the supplied buffer of JSON text and returns a JSON object tree
+// The returned object must be Released after use
+JSON* JSON::Parse(const char* buff, const char** perror)
+{
+ const char* end = 0;
+ JSON* json = new JSON();
+
+ if (!json)
+ {
+ AssignError(perror, "Error: Failed to allocate memory");
+ return 0;
+ }
+
+ end = json->parseValue(skip(buff), perror);
+ if (!end)
+ {
+ json->Release();
+ return NULL;
+ } // parse failure. ep is set.
+
+ return json;
+}
+
+//-----------------------------------------------------------------------------
+// Parser core - when encountering text, process appropriately.
+const char* JSON::parseValue(const char* buff, const char** perror)
+{
+ if (perror)
+ *perror = 0;
+
+ if (!buff)
+ return NULL; // Fail on null.
+
+ if (!strncmp(buff,"null",4))
+ {
+ Type = JSON_Null;
+ return buff+4;
+ }
+ if (!strncmp(buff,"false",5))
+ {
+ Type = JSON_Bool;
+ Value = "false";
+ dValue = 0;
+ return buff+5;
+ }
+ if (!strncmp(buff,"true",4))
+ {
+ Type = JSON_Bool;
+ Value = "true";
+ dValue = 1;
+ return buff+4;
+ }
+ if (*buff=='\"')
+ {
+ return parseString(buff, perror);
+ }
+ if (*buff=='-' || (*buff>='0' && *buff<='9'))
+ {
+ return parseNumber(buff);
+ }
+ if (*buff=='[')
+ {
+ return parseArray(buff, perror);
+ }
+ if (*buff=='{')
+ {
+ return parseObject(buff, perror);
+ }
+
+ return AssignError(perror, "Syntax Error: Invalid syntax");
+}
+
+
+//-----------------------------------------------------------------------------
+// Render a value to text.
+char* JSON::PrintValue(int depth, bool fmt)
+{
+ char *out=0;
+
+ switch (Type)
+ {
+ case JSON_Null: out = JSON_strdup("null"); break;
+ case JSON_Bool:
+ if (dValue == 0)
+ out = JSON_strdup("false");
+ else
+ out = JSON_strdup("true");
+ break;
+ case JSON_Number: out = PrintNumber(dValue); break;
+ case JSON_String: out = PrintString(Value); break;
+ case JSON_Array: out = PrintArray(depth, fmt); break;
+ case JSON_Object: out = PrintObject(depth, fmt); break;
+ case JSON_None: OVR_ASSERT_LOG(false, ("Bad JSON type.")); break;
+ }
+ return out;
+}
+
+//-----------------------------------------------------------------------------
+// Build an array object from input text and returns the text position after
+// the parsed array
+const char* JSON::parseArray(const char* buff, const char** perror)
+{
+ JSON *child;
+ if (*buff!='[')
+ {
+ return AssignError(perror, "Syntax Error: Missing opening bracket");
+ }
+
+ Type=JSON_Array;
+ buff=skip(buff+1);
+
+ if (*buff==']')
+ return buff+1; // empty array.
+
+ child = new JSON();
+ if (!child)
+ return 0; // memory fail
+ Children.PushBack(child);
+
+ buff=skip(child->parseValue(skip(buff), perror)); // skip any spacing, get the buff.
+ if (!buff)
+ return 0;
+
+ while (*buff==',')
+ {
+ JSON *new_item = new JSON();
+ if (!new_item)
+ return AssignError(perror, "Error: Failed to allocate memory");
+
+ Children.PushBack(new_item);
+
+ buff=skip(new_item->parseValue(skip(buff+1), perror));
+ if (!buff)
+ return AssignError(perror, "Error: Failed to allocate memory");
+ }
+
+ if (*buff==']')
+ return buff+1; // end of array
+
+ return AssignError(perror, "Syntax Error: Missing ending bracket");
+}
+
+//-----------------------------------------------------------------------------
+// Render an array to text. The returned text must be freed
+char* JSON::PrintArray(int depth, bool fmt)
+{
+ char **entries;
+ char * out = 0,*ptr,*ret;
+ SPInt len = 5;
+
+ bool fail = false;
+
+ // How many entries in the array?
+ int numentries = GetItemCount();
+ if (!numentries)
+ {
+ out=(char*)OVR_ALLOC(3);
+ if (out)
+ OVR_strcpy(out, 3, "[]");
+ return out;
+ }
+ // Allocate an array to hold the values for each
+ entries=(char**)OVR_ALLOC(numentries*sizeof(char*));
+ if (!entries)
+ return 0;
+ memset(entries,0,numentries*sizeof(char*));
+
+ //// Retrieve all the results:
+ JSON* child = Children.GetFirst();
+ for (int i=0; i<numentries; i++)
+ {
+ //JSON* child = Children[i];
+ ret=child->PrintValue(depth+1, fmt);
+ entries[i]=ret;
+ if (ret)
+ len+=OVR_strlen(ret)+2+(fmt?1:0);
+ else
+ {
+ fail = true;
+ break;
+ }
+ child = Children.GetNext(child);
+ }
+
+ // If we didn't fail, try to malloc the output string
+ if (!fail)
+ out=(char*)OVR_ALLOC(len);
+ // If that fails, we fail.
+ if (!out)
+ fail = true;
+
+ // Handle failure.
+ if (fail)
+ {
+ for (int i=0; i<numentries; i++)
+ {
+ if (entries[i])
+ OVR_FREE(entries[i]);
+ }
+ OVR_FREE(entries);
+ return 0;
+ }
+
+ // Compose the output array.
+ *out='[';
+ ptr=out+1;
+ *ptr=0;
+ for (int i=0; i<numentries; i++)
+ {
+ OVR_strcpy(ptr, len - (ptr-out), entries[i]);
+ ptr+=OVR_strlen(entries[i]);
+ if (i!=numentries-1)
+ {
+ *ptr++=',';
+ if (fmt)
+ *ptr++=' ';
+ *ptr=0;
+ }
+ OVR_FREE(entries[i]);
+ }
+ OVR_FREE(entries);
+ *ptr++=']';
+ *ptr++=0;
+ return out;
+}
+
+//-----------------------------------------------------------------------------
+// Build an object from the supplied text and returns the text position after
+// the parsed object
+const char* JSON::parseObject(const char* buff, const char** perror)
+{
+ if (*buff!='{')
+ {
+ return AssignError(perror, "Syntax Error: Missing opening brace");
+ }
+
+ Type=JSON_Object;
+ buff=skip(buff+1);
+ if (*buff=='}')
+ return buff+1; // empty array.
+
+ JSON* child = new JSON();
+ Children.PushBack(child);
+
+ buff=skip(child->parseString(skip(buff), perror));
+ if (!buff)
+ return 0;
+ child->Name = child->Value;
+ child->Value.Clear();
+
+ if (*buff!=':')
+ {
+ return AssignError(perror, "Syntax Error: Missing colon");
+ }
+
+ buff=skip(child->parseValue(skip(buff+1), perror)); // skip any spacing, get the value.
+ if (!buff)
+ return 0;
+
+ while (*buff==',')
+ {
+ child = new JSON();
+ if (!child)
+ return 0; // memory fail
+
+ Children.PushBack(child);
+
+ buff=skip(child->parseString(skip(buff+1), perror));
+ if (!buff)
+ return 0;
+
+ child->Name=child->Value;
+ child->Value.Clear();
+
+ if (*buff!=':')
+ {
+ return AssignError(perror, "Syntax Error: Missing colon");
+ } // fail!
+
+ // Skip any spacing, get the value.
+ buff=skip(child->parseValue(skip(buff+1), perror));
+ if (!buff)
+ return 0;
+ }
+
+ if (*buff=='}')
+ return buff+1; // end of array
+
+ return AssignError(perror, "Syntax Error: Missing closing brace");
+}
+
+//-----------------------------------------------------------------------------
+// Render an object to text. The returned string must be freed
+char* JSON::PrintObject(int depth, bool fmt)
+{
+ char** entries = 0, **names = 0;
+ char* out = 0;
+ char* ptr, *ret, *str;
+ SPInt len = 7, i = 0, j;
+ bool fail = false;
+
+ // Count the number of entries.
+ int numentries = GetItemCount();
+
+ // Explicitly handle empty object case
+ if (numentries == 0)
+ {
+ out=(char*)OVR_ALLOC(fmt?depth+3:3);
+ if (!out)
+ return 0;
+ ptr=out;
+ *ptr++='{';
+
+ if (fmt)
+ {
+ *ptr++='\n';
+ for (i=0;i<depth-1;i++)
+ *ptr++='\t';
+ }
+ *ptr++='}';
+ *ptr++=0;
+ return out;
+ }
+ // Allocate space for the names and the objects
+ entries=(char**)OVR_ALLOC(numentries*sizeof(char*));
+ if (!entries)
+ return 0;
+ names=(char**)OVR_ALLOC(numentries*sizeof(char*));
+
+ if (!names)
+ {
+ OVR_FREE(entries);
+ return 0;
+ }
+ memset(entries,0,sizeof(char*)*numentries);
+ memset(names,0,sizeof(char*)*numentries);
+
+ // Collect all the results into our arrays:
+ depth++;
+ if (fmt)
+ len+=depth;
+
+ JSON* child = Children.GetFirst();
+ while (!Children.IsNull(child))
+ {
+ names[i] = str = PrintString(child->Name);
+ entries[i++] = ret = child->PrintValue(depth, fmt);
+
+ if (str && ret)
+ {
+ len += OVR_strlen(ret)+OVR_strlen(str)+2+(fmt?2+depth:0);
+ }
+ else
+ {
+ fail = true;
+ break;
+ }
+
+ child = Children.GetNext(child);
+ }
+
+ // Try to allocate the output string
+ if (!fail)
+ out=(char*)OVR_ALLOC(len);
+ if (!out)
+ fail=true;
+
+ // Handle failure
+ if (fail)
+ {
+ for (i=0;i<numentries;i++)
+ {
+ if (names[i])
+ OVR_FREE(names[i]);
+
+ if (entries[i])
+ OVR_FREE(entries[i]);}
+
+ OVR_FREE(names);
+ OVR_FREE(entries);
+ return 0;
+ }
+
+ // Compose the output:
+ *out = '{';
+ ptr = out+1;
+ if (fmt)
+ *ptr++='\n';
+ *ptr = 0;
+
+ for (i=0; i<numentries; i++)
+ {
+ if (fmt)
+ {
+ for (j=0; j<depth; j++)
+ *ptr++ = '\t';
+ }
+ OVR_strcpy(ptr, len - (ptr-out), names[i]);
+ ptr += OVR_strlen(names[i]);
+ *ptr++ =':';
+
+ if (fmt)
+ *ptr++='\t';
+
+ OVR_strcpy(ptr, len - (ptr-out), entries[i]);
+ ptr+=OVR_strlen(entries[i]);
+
+ if (i!=numentries-1)
+ *ptr++ = ',';
+
+ if (fmt)
+ *ptr++ = '\n';
+ *ptr = 0;
+
+ OVR_FREE(names[i]);
+ OVR_FREE(entries[i]);
+ }
+
+ OVR_FREE(names);
+ OVR_FREE(entries);
+
+ if (fmt)
+ {
+ for (i=0;i<depth-1;i++)
+ *ptr++='\t';
+ }
+ *ptr++='}';
+ *ptr++=0;
+
+ return out;
+}
+
+
+
+// Returns the number of child items in the object
+// Counts the number of items in the object.
+unsigned JSON::GetItemCount() const
+{
+ unsigned count = 0;
+ for(const JSON* p = Children.GetFirst(); !Children.IsNull(p); p = p->pNext)
+ count++;
+ return count;
+}
+
+JSON* JSON::GetItemByIndex(unsigned index)
+{
+ unsigned i = 0;
+ JSON* child = 0;
+
+ if (!Children.IsEmpty())
+ {
+ child = Children.GetFirst();
+
+ while (i < index)
+ {
+ if (Children.IsNull(child->pNext))
+ {
+ child = 0;
+ break;
+ }
+ child = child->pNext;
+ i++;
+ }
+ }
+
+ return child;
+}
+
+// Returns the child item with the given name or NULL if not found
+JSON* JSON::GetItemByName(const char* name)
+{
+ JSON* child = 0;
+
+ if (!Children.IsEmpty())
+ {
+ child = Children.GetFirst();
+
+ while (OVR_strcmp(child->Name, name) != 0)
+ {
+ if (Children.IsNull(child->pNext))
+ {
+ child = 0;
+ break;
+ }
+ child = child->pNext;
+ }
+ }
+
+ return child;
+}
+
+//-----------------------------------------------------------------------------
+// Adds a new item to the end of the child list
+void JSON::AddItem(const char *string, JSON *item)
+{
+ if (!item)
+ return;
+
+ item->Name = string;
+ Children.PushBack(item);
+}
+
+/*
+
+// Removes and frees the items at the given index
+void JSON::DeleteItem(unsigned int index)
+{
+ unsigned int num_items = 0;
+ JSON* child = Children.GetFirst();
+ while (!Children.IsNull(child) && num_items < index)
+ {
+ num_items++;
+ child = Children.GetNext(child);
+ }
+
+ if (!Children.IsNull(child))
+
+ child->RemoveNode();
+ child->Release();
+ }
+}
+
+// Replaces and frees the item at the give index with the new item
+void JSON::ReplaceItem(unsigned int index, JSON* new_item)
+{
+ unsigned int num_items = 0;
+ JSON* child = Children.GetFirst();
+ while (!Children.IsNull(child) && num_items < index)
+ {
+ num_items++;
+ child = Children.GetNext(child);
+ }
+
+ if (!Children.IsNull(child))
+ {
+ child->ReplaceNodeWith(new_item);
+ child->Release();
+ }
+}
+*/
+
+// Helper function to simplify creation of a typed object
+JSON* JSON::createHelper(JSONItemType itemType, double dval, const char* strVal)
+{
+ JSON *item = new JSON(itemType);
+ if (item)
+ {
+ item->dValue = dval;
+ if (strVal)
+ item->Value = strVal;
+ }
+ return item;
+}
+
+
+//-----------------------------------------------------------------------------
+// Adds an element to an array object type
+void JSON::AddArrayElement(JSON *item)
+{
+ if (!item)
+ return;
+
+ Children.PushBack(item);
+}
+
+
+// Returns the size of an array
+int JSON::GetArraySize()
+{
+ if (Type == JSON_Array)
+ return GetItemCount();
+ else
+ return 0;
+}
+
+// Returns the number value an the give array index
+double JSON::GetArrayNumber(int index)
+{
+ if (Type == JSON_Array)
+ {
+ JSON* number = GetItemByIndex(index);
+ return number ? number->dValue : 0.0;
+ }
+ else
+ {
+ return 0;
+ }
+}
+
+// Returns the string value at the given array index
+const char* JSON::GetArrayString(int index)
+{
+ if (Type == JSON_Array)
+ {
+ JSON* number = GetItemByIndex(index);
+ return number ? number->Value : 0;
+ }
+ else
+ {
+ return 0;
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Loads and parses the given JSON file pathname and returns a JSON object tree.
+// The returned object must be Released after use.
+JSON* JSON::Load(const char* path, const char** perror)
+{
+ SysFile f;
+ if (!f.Open(path, File::Open_Read, File::Mode_Read))
+ {
+ AssignError(perror, "Failed to open file");
+ return NULL;
+ }
+
+ int len = f.GetLength();
+ UByte* buff = (UByte*)OVR_ALLOC(len);
+ int bytes = f.Read(buff, len);
+ f.Close();
+
+ if (bytes == 0 || bytes != len)
+ {
+ OVR_FREE(buff);
+ return NULL;
+ }
+
+ JSON* json = JSON::Parse((char*)buff, perror);
+ OVR_FREE(buff);
+ return json;
+}
+
+//-----------------------------------------------------------------------------
+// Serializes the JSON object and writes to the give file path
+bool JSON::Save(const char* path)
+{
+ SysFile f;
+ if (!f.Open(path, File::Open_Write | File::Open_Create | File::Open_Truncate, File::Mode_Write))
+ return false;
+
+ char* text = PrintValue(0, true);
+ if (text)
+ {
+ SPInt len = OVR_strlen(text);
+ OVR_ASSERT(len < (SPInt)(int)len);
+
+ int bytes = f.Write((UByte*)text, (int)len);
+ f.Close();
+ OVR_FREE(text);
+ return (bytes == len);
+ }
+ else
+ {
+ return false;
+ }
+}
+
+}
diff --git a/LibOVR/Src/OVR_JSON.h b/LibOVR/Src/OVR_JSON.h
new file mode 100644
index 0000000..5e5996f
--- /dev/null
+++ b/LibOVR/Src/OVR_JSON.h
@@ -0,0 +1,143 @@
+/************************************************************************************
+
+PublicHeader: None
+Filename : OVR_JSON.h
+Content : JSON format reader and writer
+Created : April 9, 2013
+Author : Brant Lewis
+Notes :
+
+Copyright : Copyright 2012 Oculus VR, Inc. All Rights reserved.
+
+Use of this software is subject to the terms of the Oculus license
+agreement provided at the time of installation or download, or which
+otherwise accompanies this software in either electronic or hard copy form.
+
+************************************************************************************/
+
+#ifndef OVR_JSON_H
+#define OVR_JSON_H
+
+#include "Kernel/OVR_RefCount.h"
+#include "Kernel/OVR_String.h"
+#include "Kernel/OVR_List.h"
+
+namespace OVR {
+
+// JSONItemType describes the type of JSON item, specifying the type of
+// data that can be obtained from it.
+enum JSONItemType
+{
+ JSON_None = 0,
+ JSON_Null = 1,
+ JSON_Bool = 2,
+ JSON_Number = 3,
+ JSON_String = 4,
+ JSON_Array = 5,
+ JSON_Object = 6
+};
+
+
+//-----------------------------------------------------------------------------
+// ***** JSON
+
+// JSON object represents a JSON node that can be either a root of the JSON tree
+// or a child item. Every node has a type that describes what is is.
+// New JSON trees are typically loaded JSON::Load or created with JSON::Parse.
+
+class JSON : public RefCountBase<JSON>, public ListNode<JSON>
+{
+protected:
+ List<JSON> Children;
+
+public:
+ JSONItemType Type; // Type of this JSON node.
+ String Name; // Name part of the {Name, Value} pair in a parent object.
+ String Value;
+ double dValue;
+
+public:
+ ~JSON();
+
+ // *** Creation of NEW JSON objects
+
+ static JSON* CreateObject() { return new JSON(JSON_Object);}
+ static JSON* CreateNull() { return new JSON(JSON_Null); }
+ static JSON* CreateArray() { return new JSON(JSON_Array); }
+ static JSON* CreateBool(bool b) { return createHelper(JSON_Bool, b ? 1.0 : 0.0); }
+ static JSON* CreateNumber(double num) { return createHelper(JSON_Number, num); }
+ static JSON* CreateString(const char *s) { return createHelper(JSON_String, 0.0, s); }
+
+ // Creates a new JSON object from parsing string.
+ // Returns null pointer and fills in *perror in case of parse error.
+ static JSON* Parse(const char* buff, const char** perror = 0);
+
+ // Loads and parses a JSON object from a file.
+ // Returns 0 and assigns perror with error message on fail.
+ static JSON* Load(const char* path, const char** perror = 0);
+
+ // Saves a JSON object to a file.
+ bool Save(const char* path);
+
+
+ // *** Object Member Access
+
+ // These provide access to child items of the list.
+ bool HasItems() const { return Children.IsEmpty(); }
+ // Returns first/last child item, or null if child list is empty
+ JSON* GetFirstItem() { return (!Children.IsEmpty()) ? Children.GetFirst() : 0; }
+ JSON* GetLastItem() { return (!Children.IsEmpty()) ? Children.GetLast() : 0; }
+
+ // Counts the number of items in the object; these methods are inefficient.
+ unsigned GetItemCount() const;
+ JSON* GetItemByIndex(unsigned i);
+ JSON* GetItemByName(const char* name);
+
+ // Returns next item in a list of children; 0 if no more items exist.
+ JSON* GetNextItem(JSON* item) { return Children.IsNull(item->pNext) ? 0 : item->pNext; }
+ JSON* GetPrevItem(JSON* item) { return Children.IsNull(item->pPrev) ? 0 : item->pPrev; }
+
+
+ // Child item access functions
+ void AddItem(const char *string, JSON* item);
+ void AddNullItem(const char* name) { AddItem(name, CreateNull()); }
+ void AddBoolItem(const char* name, bool b) { AddItem(name, CreateBool(b)); }
+ void AddNumberItem(const char* name, double n) { AddItem(name, CreateNumber(n)); }
+ void AddStringItem(const char* name, const char* s) { AddItem(name, CreateString(s)); }
+// void ReplaceItem(unsigned index, JSON* new_item);
+// void DeleteItem(unsigned index);
+
+ // *** Array Element Access
+
+ // Add new elements to the end of array.
+ void AddArrayElement(JSON *item);
+ void AddArrayNumber(double n) { AddArrayElement(CreateNumber(n)); }
+ void AddArrayString(const char* s) { AddArrayElement(CreateString(s)); }
+
+ // Accessed array elements; currently inefficient.
+ int GetArraySize();
+ double GetArrayNumber(int index);
+ const char* GetArrayString(int index);
+
+
+protected:
+ JSON(JSONItemType itemType = JSON_Object);
+
+ static JSON* createHelper(JSONItemType itemType, double dval, const char* strVal = 0);
+
+ // JSON Parsing helper functions.
+ const char* parseValue(const char *buff, const char** perror);
+ const char* parseNumber(const char *num);
+ const char* parseArray(const char* value, const char** perror);
+ const char* parseObject(const char* value, const char** perror);
+ const char* parseString(const char* str, const char** perror);
+
+ char* PrintValue(int depth, bool fmt);
+ char* PrintObject(int depth, bool fmt);
+ char* PrintArray(int depth, bool fmt);
+};
+
+
+}
+
+#endif
diff --git a/LibOVR/Src/OVR_LatencyTestImpl.cpp b/LibOVR/Src/OVR_LatencyTestImpl.cpp
index ff420a2..2bdbd52 100644
--- a/LibOVR/Src/OVR_LatencyTestImpl.cpp
+++ b/LibOVR/Src/OVR_LatencyTestImpl.cpp
@@ -1,798 +1,774 @@
-/************************************************************************************
-
-Filename : OVR_LatencyTestImpl.cpp
-Content : Oculus Latency Tester device implementation.
-Created : March 7, 2013
-Authors : Lee Cooper
-
-Copyright : Copyright 2013 Oculus VR, Inc. All Rights reserved.
-
-Use of this software is subject to the terms of the Oculus license
-agreement provided at the time of installation or download, or which
-otherwise accompanies this software in either electronic or hard copy form.
-
-*************************************************************************************/
-
-#include "OVR_LatencyTestImpl.h"
-
-namespace OVR {
-
-//-------------------------------------------------------------------------------------
-// ***** Oculus Latency Tester specific packet data structures
-
-enum {
- LatencyTester_VendorId = Oculus_VendorId,
- LatencyTester_ProductId = 0x0101,
-};
-
-// Reported data is little-endian now
-static UInt16 DecodeUInt16(const UByte* buffer)
-{
- return (UInt16(buffer[1]) << 8) | UInt16(buffer[0]);
-}
-
-/* Unreferenced
-static SInt16 DecodeSInt16(const UByte* buffer)
-{
- return (SInt16(buffer[1]) << 8) | SInt16(buffer[0]);
-}*/
-
-static void UnpackSamples(const UByte* buffer, UByte* r, UByte* g, UByte* b)
-{
- *r = buffer[0];
- *g = buffer[1];
- *b = buffer[2];
-}
-
-// Messages we handle.
-enum LatencyTestMessageType
-{
- LatencyTestMessage_None = 0,
- LatencyTestMessage_Samples = 1,
- LatencyTestMessage_ColorDetected = 2,
- LatencyTestMessage_TestStarted = 3,
- LatencyTestMessage_Button = 4,
- LatencyTestMessage_Unknown = 0x100,
- LatencyTestMessage_SizeError = 0x101,
-};
-
-struct LatencyTestSample
-{
- UByte Value[3];
-};
-
-struct LatencyTestSamples
-{
- UByte SampleCount;
- UInt16 Timestamp;
-
- LatencyTestSample Samples[20];
-
- LatencyTestMessageType Decode(const UByte* buffer, int size)
- {
- if (size < 64)
- {
- return LatencyTestMessage_SizeError;
- }
-
- SampleCount = buffer[1];
- Timestamp = DecodeUInt16(buffer + 2);
-
- for (UByte i = 0; i < SampleCount; i++)
- {
- UnpackSamples(buffer + 4 + (3 * i), &Samples[i].Value[0], &Samples[i].Value[1], &Samples[i].Value[2]);
- }
-
- return LatencyTestMessage_Samples;
- }
-};
-
-struct LatencyTestSamplesMessage
-{
- LatencyTestMessageType Type;
- LatencyTestSamples Samples;
-};
-
-bool DecodeLatencyTestSamplesMessage(LatencyTestSamplesMessage* message, UByte* buffer, int size)
-{
- memset(message, 0, sizeof(LatencyTestSamplesMessage));
-
- if (size < 64)
- {
- message->Type = LatencyTestMessage_SizeError;
- return false;
- }
-
- switch (buffer[0])
- {
- case LatencyTestMessage_Samples:
- message->Type = message->Samples.Decode(buffer, size);
- break;
-
- default:
- message->Type = LatencyTestMessage_Unknown;
- break;
- }
-
- return (message->Type < LatencyTestMessage_Unknown) && (message->Type != LatencyTestMessage_None);
-}
-
-struct LatencyTestColorDetected
-{
- UInt16 CommandID;
- UInt16 Timestamp;
- UInt16 Elapsed;
- UByte TriggerValue[3];
- UByte TargetValue[3];
-
- LatencyTestMessageType Decode(const UByte* buffer, int size)
- {
- if (size < 13)
- return LatencyTestMessage_SizeError;
-
- CommandID = DecodeUInt16(buffer + 1);
- Timestamp = DecodeUInt16(buffer + 3);
- Elapsed = DecodeUInt16(buffer + 5);
- memcpy(TriggerValue, buffer + 7, 3);
- memcpy(TargetValue, buffer + 10, 3);
-
- return LatencyTestMessage_ColorDetected;
- }
-};
-
-struct LatencyTestColorDetectedMessage
-{
- LatencyTestMessageType Type;
- LatencyTestColorDetected ColorDetected;
-};
-
-bool DecodeLatencyTestColorDetectedMessage(LatencyTestColorDetectedMessage* message, UByte* buffer, int size)
-{
- memset(message, 0, sizeof(LatencyTestColorDetectedMessage));
-
- if (size < 13)
- {
- message->Type = LatencyTestMessage_SizeError;
- return false;
- }
-
- switch (buffer[0])
- {
- case LatencyTestMessage_ColorDetected:
- message->Type = message->ColorDetected.Decode(buffer, size);
- break;
-
- default:
- message->Type = LatencyTestMessage_Unknown;
- break;
- }
-
- return (message->Type < LatencyTestMessage_Unknown) && (message->Type != LatencyTestMessage_None);
-}
-
-struct LatencyTestStarted
-{
- UInt16 CommandID;
- UInt16 Timestamp;
- UByte TargetValue[3];
-
- LatencyTestMessageType Decode(const UByte* buffer, int size)
- {
- if (size < 8)
- return LatencyTestMessage_SizeError;
-
- CommandID = DecodeUInt16(buffer + 1);
- Timestamp = DecodeUInt16(buffer + 3);
- memcpy(TargetValue, buffer + 5, 3);
-
- return LatencyTestMessage_TestStarted;
- }
-};
-
-struct LatencyTestStartedMessage
-{
- LatencyTestMessageType Type;
- LatencyTestStarted TestStarted;
-};
-
-bool DecodeLatencyTestStartedMessage(LatencyTestStartedMessage* message, UByte* buffer, int size)
-{
- memset(message, 0, sizeof(LatencyTestStartedMessage));
-
- if (size < 8)
- {
- message->Type = LatencyTestMessage_SizeError;
- return false;
- }
-
- switch (buffer[0])
- {
- case LatencyTestMessage_TestStarted:
- message->Type = message->TestStarted.Decode(buffer, size);
- break;
-
- default:
- message->Type = LatencyTestMessage_Unknown;
- break;
- }
-
- return (message->Type < LatencyTestMessage_Unknown) && (message->Type != LatencyTestMessage_None);
-}
-
-struct LatencyTestButton
-{
- UInt16 CommandID;
- UInt16 Timestamp;
-
- LatencyTestMessageType Decode(const UByte* buffer, int size)
- {
- if (size < 5)
- return LatencyTestMessage_SizeError;
-
- CommandID = DecodeUInt16(buffer + 1);
- Timestamp = DecodeUInt16(buffer + 3);
-
- return LatencyTestMessage_Button;
- }
-};
-
-struct LatencyTestButtonMessage
-{
- LatencyTestMessageType Type;
- LatencyTestButton Button;
-};
-
-bool DecodeLatencyTestButtonMessage(LatencyTestButtonMessage* message, UByte* buffer, int size)
-{
- memset(message, 0, sizeof(LatencyTestButtonMessage));
-
- if (size < 5)
- {
- message->Type = LatencyTestMessage_SizeError;
- return false;
- }
-
- switch (buffer[0])
- {
- case LatencyTestMessage_Button:
- message->Type = message->Button.Decode(buffer, size);
- break;
-
- default:
- message->Type = LatencyTestMessage_Unknown;
- break;
- }
-
- return (message->Type < LatencyTestMessage_Unknown) && (message->Type != LatencyTestMessage_None);
-}
-
-struct LatencyTestConfigurationImpl
-{
- enum { PacketSize = 5 };
- UByte Buffer[PacketSize];
-
- OVR::LatencyTestConfiguration Configuration;
-
- LatencyTestConfigurationImpl(const OVR::LatencyTestConfiguration& configuration)
- : Configuration(configuration)
- {
- Pack();
- }
-
- void Pack()
- {
- Buffer[0] = 5;
- Buffer[1] = UByte(Configuration.SendSamples);
- Buffer[2] = Configuration.Threshold.R;
- Buffer[3] = Configuration.Threshold.G;
- Buffer[4] = Configuration.Threshold.B;
- }
-
- void Unpack()
- {
- Configuration.SendSamples = Buffer[1] != 0 ? true : false;
- Configuration.Threshold.R = Buffer[2];
- Configuration.Threshold.G = Buffer[3];
- Configuration.Threshold.B = Buffer[4];
- }
-};
-
-struct LatencyTestCalibrateImpl
-{
- enum { PacketSize = 4 };
- UByte Buffer[PacketSize];
-
- OVR::LatencyTestCalibrate Calibrate;
-
- LatencyTestCalibrateImpl(const OVR::LatencyTestCalibrate& calibrate)
- : Calibrate(calibrate)
- {
- Pack();
- }
-
- void Pack()
- {
- Buffer[0] = 7;
- Buffer[1] = Calibrate.Value.R;
- Buffer[2] = Calibrate.Value.G;
- Buffer[3] = Calibrate.Value.B;
- }
-
- void Unpack()
- {
- Calibrate.Value.R = Buffer[1];
- Calibrate.Value.G = Buffer[2];
- Calibrate.Value.B = Buffer[3];
- }
-};
-
-struct LatencyTestStartTestImpl
-{
- enum { PacketSize = 6 };
- UByte Buffer[PacketSize];
-
- OVR::LatencyTestStartTest StartTest;
-
- LatencyTestStartTestImpl(const OVR::LatencyTestStartTest& startTest)
- : StartTest(startTest)
- {
- Pack();
- }
-
- void Pack()
- {
- UInt16 commandID = 1;
-
- Buffer[0] = 8;
- Buffer[1] = UByte(commandID & 0xFF);
- Buffer[2] = UByte(commandID >> 8);
- Buffer[3] = StartTest.TargetValue.R;
- Buffer[4] = StartTest.TargetValue.G;
- Buffer[5] = StartTest.TargetValue.B;
- }
-
- void Unpack()
- {
-// UInt16 commandID = Buffer[1] | (UInt16(Buffer[2]) << 8);
- StartTest.TargetValue.R = Buffer[3];
- StartTest.TargetValue.G = Buffer[4];
- StartTest.TargetValue.B = Buffer[5];
- }
-};
-
-struct LatencyTestDisplayImpl
-{
- enum { PacketSize = 6 };
- UByte Buffer[PacketSize];
-
- OVR::LatencyTestDisplay Display;
-
- LatencyTestDisplayImpl(const OVR::LatencyTestDisplay& display)
- : Display(display)
- {
- Pack();
- }
-
- void Pack()
- {
- Buffer[0] = 9;
- Buffer[1] = Display.Mode;
- Buffer[2] = UByte(Display.Value & 0xFF);
- Buffer[3] = UByte((Display.Value >> 8) & 0xFF);
- Buffer[4] = UByte((Display.Value >> 16) & 0xFF);
- Buffer[5] = UByte((Display.Value >> 24) & 0xFF);
- }
-
- void Unpack()
- {
- Display.Mode = Buffer[1];
- Display.Value = UInt32(Buffer[2]) |
- (UInt32(Buffer[3]) << 8) |
- (UInt32(Buffer[4]) << 16) |
- (UInt32(Buffer[5]) << 24);
- }
-};
-
-//-------------------------------------------------------------------------------------
-// ***** LatencyTestDeviceFactory
-
-LatencyTestDeviceFactory LatencyTestDeviceFactory::Instance;
-
-void LatencyTestDeviceFactory::EnumerateDevices(EnumerateVisitor& visitor)
-{
-
- class LatencyTestEnumerator : public HIDEnumerateVisitor
- {
- // Assign not supported; suppress MSVC warning.
- void operator = (const LatencyTestEnumerator&) { }
-
- DeviceFactory* pFactory;
- EnumerateVisitor& ExternalVisitor;
- public:
- LatencyTestEnumerator(DeviceFactory* factory, EnumerateVisitor& externalVisitor)
- : pFactory(factory), ExternalVisitor(externalVisitor) { }
-
- virtual bool MatchVendorProduct(UInt16 vendorId, UInt16 productId)
- {
- return pFactory->MatchVendorProduct(vendorId, productId);
- }
-
- virtual void Visit(HIDDevice& device, const HIDDeviceDesc& desc)
- {
- OVR_UNUSED(device);
-
- LatencyTestDeviceCreateDesc createDesc(pFactory, desc);
- ExternalVisitor.Visit(createDesc);
- }
- };
-
- LatencyTestEnumerator latencyTestEnumerator(this, visitor);
- GetManagerImpl()->GetHIDDeviceManager()->Enumerate(&latencyTestEnumerator);
-}
-
-bool LatencyTestDeviceFactory::MatchVendorProduct(UInt16 vendorId, UInt16 productId) const
-{
- return ((vendorId == LatencyTester_VendorId) && (productId == LatencyTester_ProductId));
-}
-
-bool LatencyTestDeviceFactory::DetectHIDDevice(DeviceManager* pdevMgr,
- const HIDDeviceDesc& desc)
-{
- if (MatchVendorProduct(desc.VendorId, desc.ProductId))
- {
- LatencyTestDeviceCreateDesc createDesc(this, desc);
- return pdevMgr->AddDevice_NeedsLock(createDesc).GetPtr() != NULL;
- }
- return false;
-}
-
-//-------------------------------------------------------------------------------------
-// ***** LatencyTestDeviceCreateDesc
-
-DeviceBase* LatencyTestDeviceCreateDesc::NewDeviceInstance()
-{
- return new LatencyTestDeviceImpl(this);
-}
-
-bool LatencyTestDeviceCreateDesc::GetDeviceInfo(DeviceInfo* info) const
-{
- if ((info->InfoClassType != Device_LatencyTester) &&
- (info->InfoClassType != Device_None))
- return false;
-
- OVR_strcpy(info->ProductName, DeviceInfo::MaxNameLength, HIDDesc.Product.ToCStr());
- OVR_strcpy(info->Manufacturer, DeviceInfo::MaxNameLength, HIDDesc.Manufacturer.ToCStr());
- info->Type = Device_LatencyTester;
- info->Version = 0;
-
- if (info->InfoClassType == Device_LatencyTester)
- {
- SensorInfo* sinfo = (SensorInfo*)info;
- sinfo->VendorId = HIDDesc.VendorId;
- sinfo->ProductId = HIDDesc.ProductId;
- OVR_strcpy(sinfo->SerialNumber, sizeof(sinfo->SerialNumber),HIDDesc.SerialNumber.ToCStr());
- }
- return true;
-}
-
-//-------------------------------------------------------------------------------------
-// ***** LatencyTestDevice
-
-LatencyTestDeviceImpl::LatencyTestDeviceImpl(LatencyTestDeviceCreateDesc* createDesc)
- : OVR::HIDDeviceImpl<OVR::LatencyTestDevice>(createDesc, 0)
-{
-}
-
-LatencyTestDeviceImpl::~LatencyTestDeviceImpl()
-{
- // Check that Shutdown() was called.
- OVR_ASSERT(!pCreateDesc->pDevice);
-}
-
-// Internal creation APIs.
-bool LatencyTestDeviceImpl::Initialize(DeviceBase* parent)
-{
- if (HIDDeviceImpl<OVR::LatencyTestDevice>::Initialize(parent))
- {
- LogText("OVR::LatencyTestDevice initialized.\n");
- return true;
- }
-
- return false;
-}
-
-void LatencyTestDeviceImpl::Shutdown()
-{
- HIDDeviceImpl<OVR::LatencyTestDevice>::Shutdown();
-
- LogText("OVR::LatencyTestDevice - Closed '%s'\n", getHIDDesc()->Path.ToCStr());
-}
-
-void LatencyTestDeviceImpl::OnInputReport(UByte* pData, UInt32 length)
-{
-
- bool processed = false;
- if (!processed)
- {
- LatencyTestSamplesMessage message;
- if (DecodeLatencyTestSamplesMessage(&message, pData, length))
- {
- processed = true;
- onLatencyTestSamplesMessage(&message);
- }
- }
-
- if (!processed)
- {
- LatencyTestColorDetectedMessage message;
- if (DecodeLatencyTestColorDetectedMessage(&message, pData, length))
- {
- processed = true;
- onLatencyTestColorDetectedMessage(&message);
- }
- }
-
- if (!processed)
- {
- LatencyTestStartedMessage message;
- if (DecodeLatencyTestStartedMessage(&message, pData, length))
- {
- processed = true;
- onLatencyTestStartedMessage(&message);
- }
- }
-
- if (!processed)
- {
- LatencyTestButtonMessage message;
- if (DecodeLatencyTestButtonMessage(&message, pData, length))
- {
- processed = true;
- onLatencyTestButtonMessage(&message);
- }
- }
-}
-
-bool LatencyTestDeviceImpl::SetConfiguration(const OVR::LatencyTestConfiguration& configuration, bool waitFlag)
-{
- bool result = false;
- ThreadCommandQueue* queue = GetManagerImpl()->GetThreadQueue();
-
- if (GetManagerImpl()->GetThreadId() != OVR::GetCurrentThreadId())
- {
- if (!waitFlag)
- {
- return queue->PushCall(this, &LatencyTestDeviceImpl::setConfiguration, configuration);
- }
-
- if (!queue->PushCallAndWaitResult( this,
- &LatencyTestDeviceImpl::setConfiguration,
- &result,
- configuration))
- {
- return false;
- }
- }
- else
- return setConfiguration(configuration);
-
- return result;
-}
-
-bool LatencyTestDeviceImpl::setConfiguration(const OVR::LatencyTestConfiguration& configuration)
-{
- LatencyTestConfigurationImpl ltc(configuration);
- return GetInternalDevice()->SetFeatureReport(ltc.Buffer, LatencyTestConfigurationImpl::PacketSize);
-}
-
-bool LatencyTestDeviceImpl::GetConfiguration(OVR::LatencyTestConfiguration* configuration)
-{
- bool result = false;
-
- ThreadCommandQueue* pQueue = this->GetManagerImpl()->GetThreadQueue();
- if (!pQueue->PushCallAndWaitResult(this, &LatencyTestDeviceImpl::getConfiguration, &result, configuration))
- return false;
-
- return result;
-}
-
-bool LatencyTestDeviceImpl::getConfiguration(OVR::LatencyTestConfiguration* configuration)
-{
- LatencyTestConfigurationImpl ltc(*configuration);
- if (GetInternalDevice()->GetFeatureReport(ltc.Buffer, LatencyTestConfigurationImpl::PacketSize))
- {
- ltc.Unpack();
- *configuration = ltc.Configuration;
- return true;
- }
-
- return false;
-}
-
-bool LatencyTestDeviceImpl::SetCalibrate(const OVR::LatencyTestCalibrate& calibrate, bool waitFlag)
-{
- bool result = false;
- ThreadCommandQueue* queue = GetManagerImpl()->GetThreadQueue();
-
- if (!waitFlag)
- {
- return queue->PushCall(this, &LatencyTestDeviceImpl::setCalibrate, calibrate);
- }
-
- if (!queue->PushCallAndWaitResult( this,
- &LatencyTestDeviceImpl::setCalibrate,
- &result,
- calibrate))
- {
- return false;
- }
-
- return result;
-}
-
-bool LatencyTestDeviceImpl::setCalibrate(const OVR::LatencyTestCalibrate& calibrate)
-{
- LatencyTestCalibrateImpl ltc(calibrate);
- return GetInternalDevice()->SetFeatureReport(ltc.Buffer, LatencyTestCalibrateImpl::PacketSize);
-}
-
-bool LatencyTestDeviceImpl::GetCalibrate(OVR::LatencyTestCalibrate* calibrate)
-{
- bool result = false;
-
- ThreadCommandQueue* pQueue = this->GetManagerImpl()->GetThreadQueue();
- if (!pQueue->PushCallAndWaitResult(this, &LatencyTestDeviceImpl::getCalibrate, &result, calibrate))
- return false;
-
- return result;
-}
-
-bool LatencyTestDeviceImpl::getCalibrate(OVR::LatencyTestCalibrate* calibrate)
-{
- LatencyTestCalibrateImpl ltc(*calibrate);
- if (GetInternalDevice()->GetFeatureReport(ltc.Buffer, LatencyTestCalibrateImpl::PacketSize))
- {
- ltc.Unpack();
- *calibrate = ltc.Calibrate;
- return true;
- }
-
- return false;
-}
-
-bool LatencyTestDeviceImpl::SetStartTest(const OVR::LatencyTestStartTest& start, bool waitFlag)
-{
- bool result = false;
- ThreadCommandQueue* queue = GetManagerImpl()->GetThreadQueue();
-
- if (!waitFlag)
- {
- return queue->PushCall(this, &LatencyTestDeviceImpl::setStartTest, start);
- }
-
- if (!queue->PushCallAndWaitResult( this,
- &LatencyTestDeviceImpl::setStartTest,
- &result,
- start))
- {
- return false;
- }
-
- return result;
-}
-
-bool LatencyTestDeviceImpl::setStartTest(const OVR::LatencyTestStartTest& start)
-{
- LatencyTestStartTestImpl ltst(start);
- return GetInternalDevice()->SetFeatureReport(ltst.Buffer, LatencyTestStartTestImpl::PacketSize);
-}
-
-bool LatencyTestDeviceImpl::SetDisplay(const OVR::LatencyTestDisplay& display, bool waitFlag)
-{
- bool result = false;
- ThreadCommandQueue * queue = GetManagerImpl()->GetThreadQueue();
-
- if (!waitFlag)
- {
- return queue->PushCall(this, &LatencyTestDeviceImpl::setDisplay, display);
- }
-
- if (!queue->PushCallAndWaitResult( this,
- &LatencyTestDeviceImpl::setDisplay,
- &result,
- display))
- {
- return false;
- }
-
- return result;
-}
-
-bool LatencyTestDeviceImpl::setDisplay(const OVR::LatencyTestDisplay& display)
-{
- LatencyTestDisplayImpl ltd(display);
- return GetInternalDevice()->SetFeatureReport(ltd.Buffer, LatencyTestDisplayImpl::PacketSize);
-}
-
-void LatencyTestDeviceImpl::onLatencyTestSamplesMessage(LatencyTestSamplesMessage* message)
-{
-
- if (message->Type != LatencyTestMessage_Samples)
- return;
-
- LatencyTestSamples& s = message->Samples;
-
- // Call OnMessage() within a lock to avoid conflicts with handlers.
- Lock::Locker scopeLock(HandlerRef.GetLock());
-
- if (HandlerRef.GetHandler())
- {
- MessageLatencyTestSamples samples(this);
- for (UByte i = 0; i < s.SampleCount; i++)
- {
- samples.Samples.PushBack(Color(s.Samples[i].Value[0], s.Samples[i].Value[1], s.Samples[i].Value[2]));
- }
-
- HandlerRef.GetHandler()->OnMessage(samples);
- }
-}
-
-void LatencyTestDeviceImpl::onLatencyTestColorDetectedMessage(LatencyTestColorDetectedMessage* message)
-{
- if (message->Type != LatencyTestMessage_ColorDetected)
- return;
-
- LatencyTestColorDetected& s = message->ColorDetected;
-
- // Call OnMessage() within a lock to avoid conflicts with handlers.
- Lock::Locker scopeLock(HandlerRef.GetLock());
-
- if (HandlerRef.GetHandler())
- {
- MessageLatencyTestColorDetected detected(this);
- detected.Elapsed = s.Elapsed;
- detected.DetectedValue = Color(s.TriggerValue[0], s.TriggerValue[1], s.TriggerValue[2]);
- detected.TargetValue = Color(s.TargetValue[0], s.TargetValue[1], s.TargetValue[2]);
-
- HandlerRef.GetHandler()->OnMessage(detected);
- }
-}
-
-void LatencyTestDeviceImpl::onLatencyTestStartedMessage(LatencyTestStartedMessage* message)
-{
- if (message->Type != LatencyTestMessage_TestStarted)
- return;
-
- LatencyTestStarted& ts = message->TestStarted;
-
- // Call OnMessage() within a lock to avoid conflicts with handlers.
- Lock::Locker scopeLock(HandlerRef.GetLock());
-
- if (HandlerRef.GetHandler())
- {
- MessageLatencyTestStarted started(this);
- started.TargetValue = Color(ts.TargetValue[0], ts.TargetValue[1], ts.TargetValue[2]);
-
- HandlerRef.GetHandler()->OnMessage(started);
- }
-}
-
-void LatencyTestDeviceImpl::onLatencyTestButtonMessage(LatencyTestButtonMessage* message)
-{
- if (message->Type != LatencyTestMessage_Button)
- return;
-
-// LatencyTestButton& s = message->Button;
-
- // Call OnMessage() within a lock to avoid conflicts with handlers.
- Lock::Locker scopeLock(HandlerRef.GetLock());
-
- if (HandlerRef.GetHandler())
- {
- MessageLatencyTestButton button(this);
-
- HandlerRef.GetHandler()->OnMessage(button);
- }
-}
-
-} // namespace OVR
+/************************************************************************************
+
+Filename : OVR_LatencyTestImpl.cpp
+Content : Oculus Latency Tester device implementation.
+Created : March 7, 2013
+Authors : Lee Cooper
+
+Copyright : Copyright 2013 Oculus VR, Inc. All Rights reserved.
+
+Use of this software is subject to the terms of the Oculus license
+agreement provided at the time of installation or download, or which
+otherwise accompanies this software in either electronic or hard copy form.
+
+*************************************************************************************/
+
+#include "OVR_LatencyTestImpl.h"
+
+namespace OVR {
+
+//-------------------------------------------------------------------------------------
+// ***** Oculus Latency Tester specific packet data structures
+
+enum {
+ LatencyTester_VendorId = Oculus_VendorId,
+ LatencyTester_ProductId = 0x0101,
+};
+
+// Reported data is little-endian now
+static UInt16 DecodeUInt16(const UByte* buffer)
+{
+ return (UInt16(buffer[1]) << 8) | UInt16(buffer[0]);
+}
+
+/* Unreferenced
+static SInt16 DecodeSInt16(const UByte* buffer)
+{
+ return (SInt16(buffer[1]) << 8) | SInt16(buffer[0]);
+}*/
+
+static void UnpackSamples(const UByte* buffer, UByte* r, UByte* g, UByte* b)
+{
+ *r = buffer[0];
+ *g = buffer[1];
+ *b = buffer[2];
+}
+
+// Messages we handle.
+enum LatencyTestMessageType
+{
+ LatencyTestMessage_None = 0,
+ LatencyTestMessage_Samples = 1,
+ LatencyTestMessage_ColorDetected = 2,
+ LatencyTestMessage_TestStarted = 3,
+ LatencyTestMessage_Button = 4,
+ LatencyTestMessage_Unknown = 0x100,
+ LatencyTestMessage_SizeError = 0x101,
+};
+
+struct LatencyTestSample
+{
+ UByte Value[3];
+};
+
+struct LatencyTestSamples
+{
+ UByte SampleCount;
+ UInt16 Timestamp;
+
+ LatencyTestSample Samples[20];
+
+ LatencyTestMessageType Decode(const UByte* buffer, int size)
+ {
+ if (size < 64)
+ {
+ return LatencyTestMessage_SizeError;
+ }
+
+ SampleCount = buffer[1];
+ Timestamp = DecodeUInt16(buffer + 2);
+
+ for (UByte i = 0; i < SampleCount; i++)
+ {
+ UnpackSamples(buffer + 4 + (3 * i), &Samples[i].Value[0], &Samples[i].Value[1], &Samples[i].Value[2]);
+ }
+
+ return LatencyTestMessage_Samples;
+ }
+};
+
+struct LatencyTestSamplesMessage
+{
+ LatencyTestMessageType Type;
+ LatencyTestSamples Samples;
+};
+
+bool DecodeLatencyTestSamplesMessage(LatencyTestSamplesMessage* message, UByte* buffer, int size)
+{
+ memset(message, 0, sizeof(LatencyTestSamplesMessage));
+
+ if (size < 64)
+ {
+ message->Type = LatencyTestMessage_SizeError;
+ return false;
+ }
+
+ switch (buffer[0])
+ {
+ case LatencyTestMessage_Samples:
+ message->Type = message->Samples.Decode(buffer, size);
+ break;
+
+ default:
+ message->Type = LatencyTestMessage_Unknown;
+ break;
+ }
+
+ return (message->Type < LatencyTestMessage_Unknown) && (message->Type != LatencyTestMessage_None);
+}
+
+struct LatencyTestColorDetected
+{
+ UInt16 CommandID;
+ UInt16 Timestamp;
+ UInt16 Elapsed;
+ UByte TriggerValue[3];
+ UByte TargetValue[3];
+
+ LatencyTestMessageType Decode(const UByte* buffer, int size)
+ {
+ if (size < 13)
+ return LatencyTestMessage_SizeError;
+
+ CommandID = DecodeUInt16(buffer + 1);
+ Timestamp = DecodeUInt16(buffer + 3);
+ Elapsed = DecodeUInt16(buffer + 5);
+ memcpy(TriggerValue, buffer + 7, 3);
+ memcpy(TargetValue, buffer + 10, 3);
+
+ return LatencyTestMessage_ColorDetected;
+ }
+};
+
+struct LatencyTestColorDetectedMessage
+{
+ LatencyTestMessageType Type;
+ LatencyTestColorDetected ColorDetected;
+};
+
+bool DecodeLatencyTestColorDetectedMessage(LatencyTestColorDetectedMessage* message, UByte* buffer, int size)
+{
+ memset(message, 0, sizeof(LatencyTestColorDetectedMessage));
+
+ if (size < 13)
+ {
+ message->Type = LatencyTestMessage_SizeError;
+ return false;
+ }
+
+ switch (buffer[0])
+ {
+ case LatencyTestMessage_ColorDetected:
+ message->Type = message->ColorDetected.Decode(buffer, size);
+ break;
+
+ default:
+ message->Type = LatencyTestMessage_Unknown;
+ break;
+ }
+
+ return (message->Type < LatencyTestMessage_Unknown) && (message->Type != LatencyTestMessage_None);
+}
+
+struct LatencyTestStarted
+{
+ UInt16 CommandID;
+ UInt16 Timestamp;
+ UByte TargetValue[3];
+
+ LatencyTestMessageType Decode(const UByte* buffer, int size)
+ {
+ if (size < 8)
+ return LatencyTestMessage_SizeError;
+
+ CommandID = DecodeUInt16(buffer + 1);
+ Timestamp = DecodeUInt16(buffer + 3);
+ memcpy(TargetValue, buffer + 5, 3);
+
+ return LatencyTestMessage_TestStarted;
+ }
+};
+
+struct LatencyTestStartedMessage
+{
+ LatencyTestMessageType Type;
+ LatencyTestStarted TestStarted;
+};
+
+bool DecodeLatencyTestStartedMessage(LatencyTestStartedMessage* message, UByte* buffer, int size)
+{
+ memset(message, 0, sizeof(LatencyTestStartedMessage));
+
+ if (size < 8)
+ {
+ message->Type = LatencyTestMessage_SizeError;
+ return false;
+ }
+
+ switch (buffer[0])
+ {
+ case LatencyTestMessage_TestStarted:
+ message->Type = message->TestStarted.Decode(buffer, size);
+ break;
+
+ default:
+ message->Type = LatencyTestMessage_Unknown;
+ break;
+ }
+
+ return (message->Type < LatencyTestMessage_Unknown) && (message->Type != LatencyTestMessage_None);
+}
+
+struct LatencyTestButton
+{
+ UInt16 CommandID;
+ UInt16 Timestamp;
+
+ LatencyTestMessageType Decode(const UByte* buffer, int size)
+ {
+ if (size < 5)
+ return LatencyTestMessage_SizeError;
+
+ CommandID = DecodeUInt16(buffer + 1);
+ Timestamp = DecodeUInt16(buffer + 3);
+
+ return LatencyTestMessage_Button;
+ }
+};
+
+struct LatencyTestButtonMessage
+{
+ LatencyTestMessageType Type;
+ LatencyTestButton Button;
+};
+
+bool DecodeLatencyTestButtonMessage(LatencyTestButtonMessage* message, UByte* buffer, int size)
+{
+ memset(message, 0, sizeof(LatencyTestButtonMessage));
+
+ if (size < 5)
+ {
+ message->Type = LatencyTestMessage_SizeError;
+ return false;
+ }
+
+ switch (buffer[0])
+ {
+ case LatencyTestMessage_Button:
+ message->Type = message->Button.Decode(buffer, size);
+ break;
+
+ default:
+ message->Type = LatencyTestMessage_Unknown;
+ break;
+ }
+
+ return (message->Type < LatencyTestMessage_Unknown) && (message->Type != LatencyTestMessage_None);
+}
+
+struct LatencyTestConfigurationImpl
+{
+ enum { PacketSize = 5 };
+ UByte Buffer[PacketSize];
+
+ OVR::LatencyTestConfiguration Configuration;
+
+ LatencyTestConfigurationImpl(const OVR::LatencyTestConfiguration& configuration)
+ : Configuration(configuration)
+ {
+ Pack();
+ }
+
+ void Pack()
+ {
+ Buffer[0] = 5;
+ Buffer[1] = UByte(Configuration.SendSamples);
+ Buffer[2] = Configuration.Threshold.R;
+ Buffer[3] = Configuration.Threshold.G;
+ Buffer[4] = Configuration.Threshold.B;
+ }
+
+ void Unpack()
+ {
+ Configuration.SendSamples = Buffer[1] != 0 ? true : false;
+ Configuration.Threshold.R = Buffer[2];
+ Configuration.Threshold.G = Buffer[3];
+ Configuration.Threshold.B = Buffer[4];
+ }
+};
+
+struct LatencyTestCalibrateImpl
+{
+ enum { PacketSize = 4 };
+ UByte Buffer[PacketSize];
+
+ Color CalibrationColor;
+
+ LatencyTestCalibrateImpl(const Color& calibrationColor)
+ : CalibrationColor(calibrationColor)
+ {
+ Pack();
+ }
+
+ void Pack()
+ {
+ Buffer[0] = 7;
+ Buffer[1] = CalibrationColor.R;
+ Buffer[2] = CalibrationColor.G;
+ Buffer[3] = CalibrationColor.B;
+ }
+
+ void Unpack()
+ {
+ CalibrationColor.R = Buffer[1];
+ CalibrationColor.G = Buffer[2];
+ CalibrationColor.B = Buffer[3];
+ }
+};
+
+struct LatencyTestStartTestImpl
+{
+ enum { PacketSize = 6 };
+ UByte Buffer[PacketSize];
+
+ Color TargetColor;
+
+ LatencyTestStartTestImpl(const Color& targetColor)
+ : TargetColor(targetColor)
+ {
+ Pack();
+ }
+
+ void Pack()
+ {
+ UInt16 commandID = 1;
+
+ Buffer[0] = 8;
+ Buffer[1] = UByte(commandID & 0xFF);
+ Buffer[2] = UByte(commandID >> 8);
+ Buffer[3] = TargetColor.R;
+ Buffer[4] = TargetColor.G;
+ Buffer[5] = TargetColor.B;
+ }
+
+ void Unpack()
+ {
+// UInt16 commandID = Buffer[1] | (UInt16(Buffer[2]) << 8);
+ TargetColor.R = Buffer[3];
+ TargetColor.G = Buffer[4];
+ TargetColor.B = Buffer[5];
+ }
+};
+
+struct LatencyTestDisplayImpl
+{
+ enum { PacketSize = 6 };
+ UByte Buffer[PacketSize];
+
+ OVR::LatencyTestDisplay Display;
+
+ LatencyTestDisplayImpl(const OVR::LatencyTestDisplay& display)
+ : Display(display)
+ {
+ Pack();
+ }
+
+ void Pack()
+ {
+ Buffer[0] = 9;
+ Buffer[1] = Display.Mode;
+ Buffer[2] = UByte(Display.Value & 0xFF);
+ Buffer[3] = UByte((Display.Value >> 8) & 0xFF);
+ Buffer[4] = UByte((Display.Value >> 16) & 0xFF);
+ Buffer[5] = UByte((Display.Value >> 24) & 0xFF);
+ }
+
+ void Unpack()
+ {
+ Display.Mode = Buffer[1];
+ Display.Value = UInt32(Buffer[2]) |
+ (UInt32(Buffer[3]) << 8) |
+ (UInt32(Buffer[4]) << 16) |
+ (UInt32(Buffer[5]) << 24);
+ }
+};
+
+//-------------------------------------------------------------------------------------
+// ***** LatencyTestDeviceFactory
+
+LatencyTestDeviceFactory LatencyTestDeviceFactory::Instance;
+
+void LatencyTestDeviceFactory::EnumerateDevices(EnumerateVisitor& visitor)
+{
+
+ class LatencyTestEnumerator : public HIDEnumerateVisitor
+ {
+ // Assign not supported; suppress MSVC warning.
+ void operator = (const LatencyTestEnumerator&) { }
+
+ DeviceFactory* pFactory;
+ EnumerateVisitor& ExternalVisitor;
+ public:
+ LatencyTestEnumerator(DeviceFactory* factory, EnumerateVisitor& externalVisitor)
+ : pFactory(factory), ExternalVisitor(externalVisitor) { }
+
+ virtual bool MatchVendorProduct(UInt16 vendorId, UInt16 productId)
+ {
+ return pFactory->MatchVendorProduct(vendorId, productId);
+ }
+
+ virtual void Visit(HIDDevice& device, const HIDDeviceDesc& desc)
+ {
+ OVR_UNUSED(device);
+
+ LatencyTestDeviceCreateDesc createDesc(pFactory, desc);
+ ExternalVisitor.Visit(createDesc);
+ }
+ };
+
+ LatencyTestEnumerator latencyTestEnumerator(this, visitor);
+ GetManagerImpl()->GetHIDDeviceManager()->Enumerate(&latencyTestEnumerator);
+}
+
+bool LatencyTestDeviceFactory::MatchVendorProduct(UInt16 vendorId, UInt16 productId) const
+{
+ return ((vendorId == LatencyTester_VendorId) && (productId == LatencyTester_ProductId));
+}
+
+bool LatencyTestDeviceFactory::DetectHIDDevice(DeviceManager* pdevMgr,
+ const HIDDeviceDesc& desc)
+{
+ if (MatchVendorProduct(desc.VendorId, desc.ProductId))
+ {
+ LatencyTestDeviceCreateDesc createDesc(this, desc);
+ return pdevMgr->AddDevice_NeedsLock(createDesc).GetPtr() != NULL;
+ }
+ return false;
+}
+
+//-------------------------------------------------------------------------------------
+// ***** LatencyTestDeviceCreateDesc
+
+DeviceBase* LatencyTestDeviceCreateDesc::NewDeviceInstance()
+{
+ return new LatencyTestDeviceImpl(this);
+}
+
+bool LatencyTestDeviceCreateDesc::GetDeviceInfo(DeviceInfo* info) const
+{
+ if ((info->InfoClassType != Device_LatencyTester) &&
+ (info->InfoClassType != Device_None))
+ return false;
+
+ OVR_strcpy(info->ProductName, DeviceInfo::MaxNameLength, HIDDesc.Product.ToCStr());
+ OVR_strcpy(info->Manufacturer, DeviceInfo::MaxNameLength, HIDDesc.Manufacturer.ToCStr());
+ info->Type = Device_LatencyTester;
+ info->Version = 0;
+
+ if (info->InfoClassType == Device_LatencyTester)
+ {
+ SensorInfo* sinfo = (SensorInfo*)info;
+ sinfo->VendorId = HIDDesc.VendorId;
+ sinfo->ProductId = HIDDesc.ProductId;
+ OVR_strcpy(sinfo->SerialNumber, sizeof(sinfo->SerialNumber),HIDDesc.SerialNumber.ToCStr());
+ }
+ return true;
+}
+
+//-------------------------------------------------------------------------------------
+// ***** LatencyTestDevice
+
+LatencyTestDeviceImpl::LatencyTestDeviceImpl(LatencyTestDeviceCreateDesc* createDesc)
+ : OVR::HIDDeviceImpl<OVR::LatencyTestDevice>(createDesc, 0)
+{
+}
+
+LatencyTestDeviceImpl::~LatencyTestDeviceImpl()
+{
+ // Check that Shutdown() was called.
+ OVR_ASSERT(!pCreateDesc->pDevice);
+}
+
+// Internal creation APIs.
+bool LatencyTestDeviceImpl::Initialize(DeviceBase* parent)
+{
+ if (HIDDeviceImpl<OVR::LatencyTestDevice>::Initialize(parent))
+ {
+ LogText("OVR::LatencyTestDevice initialized.\n");
+ return true;
+ }
+
+ return false;
+}
+
+void LatencyTestDeviceImpl::Shutdown()
+{
+ HIDDeviceImpl<OVR::LatencyTestDevice>::Shutdown();
+
+ LogText("OVR::LatencyTestDevice - Closed '%s'\n", getHIDDesc()->Path.ToCStr());
+}
+
+void LatencyTestDeviceImpl::OnInputReport(UByte* pData, UInt32 length)
+{
+
+ bool processed = false;
+ if (!processed)
+ {
+ LatencyTestSamplesMessage message;
+ if (DecodeLatencyTestSamplesMessage(&message, pData, length))
+ {
+ processed = true;
+ onLatencyTestSamplesMessage(&message);
+ }
+ }
+
+ if (!processed)
+ {
+ LatencyTestColorDetectedMessage message;
+ if (DecodeLatencyTestColorDetectedMessage(&message, pData, length))
+ {
+ processed = true;
+ onLatencyTestColorDetectedMessage(&message);
+ }
+ }
+
+ if (!processed)
+ {
+ LatencyTestStartedMessage message;
+ if (DecodeLatencyTestStartedMessage(&message, pData, length))
+ {
+ processed = true;
+ onLatencyTestStartedMessage(&message);
+ }
+ }
+
+ if (!processed)
+ {
+ LatencyTestButtonMessage message;
+ if (DecodeLatencyTestButtonMessage(&message, pData, length))
+ {
+ processed = true;
+ onLatencyTestButtonMessage(&message);
+ }
+ }
+}
+
+bool LatencyTestDeviceImpl::SetConfiguration(const OVR::LatencyTestConfiguration& configuration, bool waitFlag)
+{
+ bool result = false;
+ ThreadCommandQueue* queue = GetManagerImpl()->GetThreadQueue();
+
+ if (GetManagerImpl()->GetThreadId() != OVR::GetCurrentThreadId())
+ {
+ if (!waitFlag)
+ {
+ return queue->PushCall(this, &LatencyTestDeviceImpl::setConfiguration, configuration);
+ }
+
+ if (!queue->PushCallAndWaitResult( this,
+ &LatencyTestDeviceImpl::setConfiguration,
+ &result,
+ configuration))
+ {
+ return false;
+ }
+ }
+ else
+ return setConfiguration(configuration);
+
+ return result;
+}
+
+bool LatencyTestDeviceImpl::setConfiguration(const OVR::LatencyTestConfiguration& configuration)
+{
+ LatencyTestConfigurationImpl ltc(configuration);
+ return GetInternalDevice()->SetFeatureReport(ltc.Buffer, LatencyTestConfigurationImpl::PacketSize);
+}
+
+bool LatencyTestDeviceImpl::GetConfiguration(OVR::LatencyTestConfiguration* configuration)
+{
+ bool result = false;
+
+ ThreadCommandQueue* pQueue = this->GetManagerImpl()->GetThreadQueue();
+ if (!pQueue->PushCallAndWaitResult(this, &LatencyTestDeviceImpl::getConfiguration, &result, configuration))
+ return false;
+
+ return result;
+}
+
+bool LatencyTestDeviceImpl::getConfiguration(OVR::LatencyTestConfiguration* configuration)
+{
+ LatencyTestConfigurationImpl ltc(*configuration);
+ if (GetInternalDevice()->GetFeatureReport(ltc.Buffer, LatencyTestConfigurationImpl::PacketSize))
+ {
+ ltc.Unpack();
+ *configuration = ltc.Configuration;
+ return true;
+ }
+
+ return false;
+}
+
+bool LatencyTestDeviceImpl::SetCalibrate(const Color& calibrationColor, bool waitFlag)
+{
+ bool result = false;
+ ThreadCommandQueue* queue = GetManagerImpl()->GetThreadQueue();
+
+ if (!waitFlag)
+ {
+ return queue->PushCall(this, &LatencyTestDeviceImpl::setCalibrate, calibrationColor);
+ }
+
+ if (!queue->PushCallAndWaitResult( this,
+ &LatencyTestDeviceImpl::setCalibrate,
+ &result,
+ calibrationColor))
+ {
+ return false;
+ }
+
+ return result;
+}
+
+bool LatencyTestDeviceImpl::setCalibrate(const Color& calibrationColor)
+{
+ LatencyTestCalibrateImpl ltc(calibrationColor);
+ return GetInternalDevice()->SetFeatureReport(ltc.Buffer, LatencyTestCalibrateImpl::PacketSize);
+}
+
+bool LatencyTestDeviceImpl::SetStartTest(const Color& targetColor, bool waitFlag)
+{
+ bool result = false;
+ ThreadCommandQueue* queue = GetManagerImpl()->GetThreadQueue();
+
+ if (!waitFlag)
+ {
+ return queue->PushCall(this, &LatencyTestDeviceImpl::setStartTest, targetColor);
+ }
+
+ if (!queue->PushCallAndWaitResult( this,
+ &LatencyTestDeviceImpl::setStartTest,
+ &result,
+ targetColor))
+ {
+ return false;
+ }
+
+ return result;
+}
+
+bool LatencyTestDeviceImpl::setStartTest(const Color& targetColor)
+{
+ LatencyTestStartTestImpl ltst(targetColor);
+ return GetInternalDevice()->SetFeatureReport(ltst.Buffer, LatencyTestStartTestImpl::PacketSize);
+}
+
+bool LatencyTestDeviceImpl::SetDisplay(const OVR::LatencyTestDisplay& display, bool waitFlag)
+{
+ bool result = false;
+ ThreadCommandQueue * queue = GetManagerImpl()->GetThreadQueue();
+
+ if (!waitFlag)
+ {
+ return queue->PushCall(this, &LatencyTestDeviceImpl::setDisplay, display);
+ }
+
+ if (!queue->PushCallAndWaitResult( this,
+ &LatencyTestDeviceImpl::setDisplay,
+ &result,
+ display))
+ {
+ return false;
+ }
+
+ return result;
+}
+
+bool LatencyTestDeviceImpl::setDisplay(const OVR::LatencyTestDisplay& display)
+{
+ LatencyTestDisplayImpl ltd(display);
+ return GetInternalDevice()->SetFeatureReport(ltd.Buffer, LatencyTestDisplayImpl::PacketSize);
+}
+
+void LatencyTestDeviceImpl::onLatencyTestSamplesMessage(LatencyTestSamplesMessage* message)
+{
+
+ if (message->Type != LatencyTestMessage_Samples)
+ return;
+
+ LatencyTestSamples& s = message->Samples;
+
+ // Call OnMessage() within a lock to avoid conflicts with handlers.
+ Lock::Locker scopeLock(HandlerRef.GetLock());
+
+ if (HandlerRef.GetHandler())
+ {
+ MessageLatencyTestSamples samples(this);
+ for (UByte i = 0; i < s.SampleCount; i++)
+ {
+ samples.Samples.PushBack(Color(s.Samples[i].Value[0], s.Samples[i].Value[1], s.Samples[i].Value[2]));
+ }
+
+ HandlerRef.GetHandler()->OnMessage(samples);
+ }
+}
+
+void LatencyTestDeviceImpl::onLatencyTestColorDetectedMessage(LatencyTestColorDetectedMessage* message)
+{
+ if (message->Type != LatencyTestMessage_ColorDetected)
+ return;
+
+ LatencyTestColorDetected& s = message->ColorDetected;
+
+ // Call OnMessage() within a lock to avoid conflicts with handlers.
+ Lock::Locker scopeLock(HandlerRef.GetLock());
+
+ if (HandlerRef.GetHandler())
+ {
+ MessageLatencyTestColorDetected detected(this);
+ detected.Elapsed = s.Elapsed;
+ detected.DetectedValue = Color(s.TriggerValue[0], s.TriggerValue[1], s.TriggerValue[2]);
+ detected.TargetValue = Color(s.TargetValue[0], s.TargetValue[1], s.TargetValue[2]);
+
+ HandlerRef.GetHandler()->OnMessage(detected);
+ }
+}
+
+void LatencyTestDeviceImpl::onLatencyTestStartedMessage(LatencyTestStartedMessage* message)
+{
+ if (message->Type != LatencyTestMessage_TestStarted)
+ return;
+
+ LatencyTestStarted& ts = message->TestStarted;
+
+ // Call OnMessage() within a lock to avoid conflicts with handlers.
+ Lock::Locker scopeLock(HandlerRef.GetLock());
+
+ if (HandlerRef.GetHandler())
+ {
+ MessageLatencyTestStarted started(this);
+ started.TargetValue = Color(ts.TargetValue[0], ts.TargetValue[1], ts.TargetValue[2]);
+
+ HandlerRef.GetHandler()->OnMessage(started);
+ }
+}
+
+void LatencyTestDeviceImpl::onLatencyTestButtonMessage(LatencyTestButtonMessage* message)
+{
+ if (message->Type != LatencyTestMessage_Button)
+ return;
+
+// LatencyTestButton& s = message->Button;
+
+ // Call OnMessage() within a lock to avoid conflicts with handlers.
+ Lock::Locker scopeLock(HandlerRef.GetLock());
+
+ if (HandlerRef.GetHandler())
+ {
+ MessageLatencyTestButton button(this);
+
+ HandlerRef.GetHandler()->OnMessage(button);
+ }
+}
+
+} // namespace OVR
diff --git a/LibOVR/Src/OVR_LatencyTestImpl.h b/LibOVR/Src/OVR_LatencyTestImpl.h
index 9217f57..727e36e 100644
--- a/LibOVR/Src/OVR_LatencyTestImpl.h
+++ b/LibOVR/Src/OVR_LatencyTestImpl.h
@@ -1,135 +1,133 @@
-/************************************************************************************
-
-Filename : OVR_LatencyTestImpl.h
-Content : Latency Tester specific implementation.
-Created : March 7, 2013
-Authors : Lee Cooper
-
-Copyright : Copyright 2013 Oculus VR, Inc. All Rights reserved.
-
-Use of this software is subject to the terms of the Oculus license
-agreement provided at the time of installation or download, or which
-otherwise accompanies this software in either electronic or hard copy form.
-
-*************************************************************************************/
-
-#ifndef OVR_LatencyTestImpl_h
-#define OVR_LatencyTestImpl_h
-
-#include "OVR_HIDDeviceImpl.h"
-
-namespace OVR {
-
-struct LatencyTestSamplesMessage;
-struct LatencyTestButtonMessage;
-struct LatencyTestStartedMessage;
-struct LatencyTestColorDetectedMessage;
-
-//-------------------------------------------------------------------------------------
-// LatencyTestDeviceFactory enumerates Oculus Latency Tester devices.
-class LatencyTestDeviceFactory : public DeviceFactory
-{
-public:
- static LatencyTestDeviceFactory Instance;
-
- // Enumerates devices, creating and destroying relevant objects in manager.
- virtual void EnumerateDevices(EnumerateVisitor& visitor);
-
- virtual bool MatchVendorProduct(UInt16 vendorId, UInt16 productId) const;
- virtual bool DetectHIDDevice(DeviceManager* pdevMgr, const HIDDeviceDesc& desc);
-
-protected:
- DeviceManager* getManager() const { return (DeviceManager*) pManager; }
-};
-
-
-// Describes a single a Oculus Latency Tester device and supports creating its instance.
-class LatencyTestDeviceCreateDesc : public HIDDeviceCreateDesc
-{
-public:
- LatencyTestDeviceCreateDesc(DeviceFactory* factory, const HIDDeviceDesc& hidDesc)
- : HIDDeviceCreateDesc(factory, Device_LatencyTester, hidDesc) { }
-
- virtual DeviceCreateDesc* Clone() const
- {
- return new LatencyTestDeviceCreateDesc(*this);
- }
-
- virtual DeviceBase* NewDeviceInstance();
-
- virtual MatchResult MatchDevice(const DeviceCreateDesc& other,
- DeviceCreateDesc**) const
- {
- if ((other.Type == Device_LatencyTester) && (pFactory == other.pFactory))
- {
- const LatencyTestDeviceCreateDesc& s2 = (const LatencyTestDeviceCreateDesc&) other;
- if (MatchHIDDevice(s2.HIDDesc))
- return Match_Found;
- }
- return Match_None;
- }
-
- virtual bool MatchHIDDevice(const HIDDeviceDesc& hidDesc) const
- {
- // should paths comparison be case insensitive?
- return ((HIDDesc.Path.CompareNoCase(hidDesc.Path) == 0) &&
- (HIDDesc.SerialNumber == hidDesc.SerialNumber));
- }
- virtual bool GetDeviceInfo(DeviceInfo* info) const;
-};
-
-
-//-------------------------------------------------------------------------------------
-// ***** OVR::LatencyTestDeviceImpl
-
-// Oculus Latency Tester interface.
-
-class LatencyTestDeviceImpl : public HIDDeviceImpl<OVR::LatencyTestDevice>
-{
-public:
- LatencyTestDeviceImpl(LatencyTestDeviceCreateDesc* createDesc);
- ~LatencyTestDeviceImpl();
-
- // DeviceCommon interface.
- virtual bool Initialize(DeviceBase* parent);
- virtual void Shutdown();
-
- // DeviceManagerThread::Notifier interface.
- virtual void OnInputReport(UByte* pData, UInt32 length);
-
- // LatencyTesterDevice interface
- virtual bool SetConfiguration(const OVR::LatencyTestConfiguration& configuration, bool waitFlag = false);
- virtual bool GetConfiguration(OVR::LatencyTestConfiguration* configuration);
-
- virtual bool SetCalibrate(const OVR::LatencyTestCalibrate& calibrate, bool waitFlag = false);
- virtual bool GetCalibrate(OVR::LatencyTestCalibrate* calibrate);
-
- virtual bool SetStartTest(const OVR::LatencyTestStartTest& start, bool waitFlag = false);
- virtual bool SetDisplay(const LatencyTestDisplay& display, bool waitFlag = false);
-
-protected:
- bool openDevice(const char** errorFormatString);
- void closeDevice();
- void closeDeviceOnIOError();
-
- bool initializeRead();
- bool processReadResult();
-
- bool setConfiguration(const OVR::LatencyTestConfiguration& configuration);
- bool getConfiguration(OVR::LatencyTestConfiguration* configuration);
- bool setCalibrate(const OVR::LatencyTestCalibrate& calibrate);
- bool getCalibrate(OVR::LatencyTestCalibrate* calibrate);
- bool setStartTest(const OVR::LatencyTestStartTest& start);
- bool setDisplay(const OVR::LatencyTestDisplay& display);
-
- // Called for decoded messages
- void onLatencyTestSamplesMessage(LatencyTestSamplesMessage* message);
- void onLatencyTestButtonMessage(LatencyTestButtonMessage* message);
- void onLatencyTestStartedMessage(LatencyTestStartedMessage* message);
- void onLatencyTestColorDetectedMessage(LatencyTestColorDetectedMessage* message);
-
-};
-
-} // namespace OVR
-
-#endif // OVR_LatencyTestImpl_h
+/************************************************************************************
+
+Filename : OVR_LatencyTestImpl.h
+Content : Latency Tester specific implementation.
+Created : March 7, 2013
+Authors : Lee Cooper
+
+Copyright : Copyright 2013 Oculus VR, Inc. All Rights reserved.
+
+Use of this software is subject to the terms of the Oculus license
+agreement provided at the time of installation or download, or which
+otherwise accompanies this software in either electronic or hard copy form.
+
+*************************************************************************************/
+
+#ifndef OVR_LatencyTestImpl_h
+#define OVR_LatencyTestImpl_h
+
+#include "OVR_HIDDeviceImpl.h"
+
+namespace OVR {
+
+struct LatencyTestSamplesMessage;
+struct LatencyTestButtonMessage;
+struct LatencyTestStartedMessage;
+struct LatencyTestColorDetectedMessage;
+
+//-------------------------------------------------------------------------------------
+// LatencyTestDeviceFactory enumerates Oculus Latency Tester devices.
+class LatencyTestDeviceFactory : public DeviceFactory
+{
+public:
+ static LatencyTestDeviceFactory Instance;
+
+ // Enumerates devices, creating and destroying relevant objects in manager.
+ virtual void EnumerateDevices(EnumerateVisitor& visitor);
+
+ virtual bool MatchVendorProduct(UInt16 vendorId, UInt16 productId) const;
+ virtual bool DetectHIDDevice(DeviceManager* pdevMgr, const HIDDeviceDesc& desc);
+
+protected:
+ DeviceManager* getManager() const { return (DeviceManager*) pManager; }
+};
+
+
+// Describes a single a Oculus Latency Tester device and supports creating its instance.
+class LatencyTestDeviceCreateDesc : public HIDDeviceCreateDesc
+{
+public:
+ LatencyTestDeviceCreateDesc(DeviceFactory* factory, const HIDDeviceDesc& hidDesc)
+ : HIDDeviceCreateDesc(factory, Device_LatencyTester, hidDesc) { }
+
+ virtual DeviceCreateDesc* Clone() const
+ {
+ return new LatencyTestDeviceCreateDesc(*this);
+ }
+
+ virtual DeviceBase* NewDeviceInstance();
+
+ virtual MatchResult MatchDevice(const DeviceCreateDesc& other,
+ DeviceCreateDesc**) const
+ {
+ if ((other.Type == Device_LatencyTester) && (pFactory == other.pFactory))
+ {
+ const LatencyTestDeviceCreateDesc& s2 = (const LatencyTestDeviceCreateDesc&) other;
+ if (MatchHIDDevice(s2.HIDDesc))
+ return Match_Found;
+ }
+ return Match_None;
+ }
+
+ virtual bool MatchHIDDevice(const HIDDeviceDesc& hidDesc) const
+ {
+ // should paths comparison be case insensitive?
+ return ((HIDDesc.Path.CompareNoCase(hidDesc.Path) == 0) &&
+ (HIDDesc.SerialNumber == hidDesc.SerialNumber));
+ }
+ virtual bool GetDeviceInfo(DeviceInfo* info) const;
+};
+
+
+//-------------------------------------------------------------------------------------
+// ***** OVR::LatencyTestDeviceImpl
+
+// Oculus Latency Tester interface.
+
+class LatencyTestDeviceImpl : public HIDDeviceImpl<OVR::LatencyTestDevice>
+{
+public:
+ LatencyTestDeviceImpl(LatencyTestDeviceCreateDesc* createDesc);
+ ~LatencyTestDeviceImpl();
+
+ // DeviceCommon interface.
+ virtual bool Initialize(DeviceBase* parent);
+ virtual void Shutdown();
+
+ // DeviceManagerThread::Notifier interface.
+ virtual void OnInputReport(UByte* pData, UInt32 length);
+
+ // LatencyTesterDevice interface
+ virtual bool SetConfiguration(const OVR::LatencyTestConfiguration& configuration, bool waitFlag = false);
+ virtual bool GetConfiguration(OVR::LatencyTestConfiguration* configuration);
+
+ virtual bool SetCalibrate(const Color& calibrationColor, bool waitFlag = false);
+
+ virtual bool SetStartTest(const Color& targetColor, bool waitFlag = false);
+ virtual bool SetDisplay(const LatencyTestDisplay& display, bool waitFlag = false);
+
+protected:
+ bool openDevice(const char** errorFormatString);
+ void closeDevice();
+ void closeDeviceOnIOError();
+
+ bool initializeRead();
+ bool processReadResult();
+
+ bool setConfiguration(const OVR::LatencyTestConfiguration& configuration);
+ bool getConfiguration(OVR::LatencyTestConfiguration* configuration);
+ bool setCalibrate(const Color& calibrationColor);
+ bool setStartTest(const Color& targetColor);
+ bool setDisplay(const OVR::LatencyTestDisplay& display);
+
+ // Called for decoded messages
+ void onLatencyTestSamplesMessage(LatencyTestSamplesMessage* message);
+ void onLatencyTestButtonMessage(LatencyTestButtonMessage* message);
+ void onLatencyTestStartedMessage(LatencyTestStartedMessage* message);
+ void onLatencyTestColorDetectedMessage(LatencyTestColorDetectedMessage* message);
+
+};
+
+} // namespace OVR
+
+#endif // OVR_LatencyTestImpl_h
diff --git a/LibOVR/Src/OVR_Linux_DeviceManager.cpp b/LibOVR/Src/OVR_Linux_DeviceManager.cpp
new file mode 100644
index 0000000..d573455
--- /dev/null
+++ b/LibOVR/Src/OVR_Linux_DeviceManager.cpp
@@ -0,0 +1,319 @@
+/************************************************************************************
+
+Filename : OVR_Linux_DeviceManager.h
+Content : Linux implementation of DeviceManager.
+Created :
+Authors :
+
+Copyright : Copyright 2012 Oculus VR, Inc. All Rights reserved.
+
+Use of this software is subject to the terms of the Oculus license
+agreement provided at the time of installation or download, or which
+otherwise accompanies this software in either electronic or hard copy form.
+
+*************************************************************************************/
+
+#include "OVR_Linux_DeviceManager.h"
+
+// Sensor & HMD Factories
+#include "OVR_LatencyTestImpl.h"
+#include "OVR_SensorImpl.h"
+#include "OVR_Linux_HIDDevice.h"
+#include "OVR_Linux_HMDDevice.h"
+
+#include "Kernel/OVR_Timer.h"
+#include "Kernel/OVR_Std.h"
+#include "Kernel/OVR_Log.h"
+
+namespace OVR { namespace Linux {
+
+
+//-------------------------------------------------------------------------------------
+// **** Linux::DeviceManager
+
+DeviceManager::DeviceManager()
+{
+}
+
+DeviceManager::~DeviceManager()
+{
+}
+
+bool DeviceManager::Initialize(DeviceBase*)
+{
+ if (!DeviceManagerImpl::Initialize(0))
+ return false;
+
+ pThread = *new DeviceManagerThread();
+ if (!pThread || !pThread->Start())
+ return false;
+
+ // Wait for the thread to be fully up and running.
+ pThread->StartupEvent.Wait();
+
+ // Do this now that we know the thread's run loop.
+ HidDeviceManager = *HIDDeviceManager::CreateInternal(this);
+
+ pCreateDesc->pDevice = this;
+ LogText("OVR::DeviceManager - initialized.\n");
+ return true;
+}
+
+void DeviceManager::Shutdown()
+{
+ LogText("OVR::DeviceManager - shutting down.\n");
+
+ // Set Manager shutdown marker variable; this prevents
+ // any existing DeviceHandle objects from accessing device.
+ pCreateDesc->pLock->pManager = 0;
+
+ // Push for thread shutdown *WITH NO WAIT*.
+ // This will have the following effect:
+ // - Exit command will get enqueued, which will be executed later on the thread itself.
+ // - Beyond this point, this DeviceManager object may be deleted by our caller.
+ // - Other commands, such as CreateDevice, may execute before ExitCommand, but they will
+ // fail gracefully due to pLock->pManager == 0. Future commands can't be enqued
+ // after pManager is null.
+ // - Once ExitCommand executes, ThreadCommand::Run loop will exit and release the last
+ // reference to the thread object.
+ pThread->PushExitCommand(false);
+ pThread.Clear();
+
+ DeviceManagerImpl::Shutdown();
+}
+
+ThreadCommandQueue* DeviceManager::GetThreadQueue()
+{
+ return pThread;
+}
+
+ThreadId DeviceManager::GetThreadId() const
+{
+ return pThread->GetThreadId();
+}
+
+bool DeviceManager::GetDeviceInfo(DeviceInfo* info) const
+{
+ if ((info->InfoClassType != Device_Manager) &&
+ (info->InfoClassType != Device_None))
+ return false;
+
+ info->Type = Device_Manager;
+ info->Version = 0;
+ OVR_strcpy(info->ProductName, DeviceInfo::MaxNameLength, "DeviceManager");
+ OVR_strcpy(info->Manufacturer,DeviceInfo::MaxNameLength, "Oculus VR, Inc.");
+ return true;
+}
+
+DeviceEnumerator<> DeviceManager::EnumerateDevicesEx(const DeviceEnumerationArgs& args)
+{
+ // TBD: Can this be avoided in the future, once proper device notification is in place?
+ pThread->PushCall((DeviceManagerImpl*)this,
+ &DeviceManager::EnumerateAllFactoryDevices, true);
+
+ return DeviceManagerImpl::EnumerateDevicesEx(args);
+}
+
+
+//-------------------------------------------------------------------------------------
+// ***** DeviceManager Thread
+
+DeviceManagerThread::DeviceManagerThread()
+ : Thread(ThreadStackSize)
+{
+ int result = pipe(CommandFd);
+ OVR_ASSERT(!result);
+
+ AddSelectFd(NULL, CommandFd[0]);
+}
+
+DeviceManagerThread::~DeviceManagerThread()
+{
+ if (CommandFd[0])
+ {
+ RemoveSelectFd(NULL, CommandFd[0]);
+ close(CommandFd[0]);
+ close(CommandFd[1]);
+ }
+}
+
+bool DeviceManagerThread::AddSelectFd(Notifier* notify, int fd)
+{
+ struct pollfd pfd;
+ pfd.fd = fd;
+ pfd.events = POLLIN|POLLHUP|POLLERR;
+ pfd.revents = 0;
+
+ FdNotifiers.PushBack(notify);
+ PollFds.PushBack(pfd);
+
+ OVR_ASSERT(FdNotifiers.GetSize() == PollFds.GetSize());
+ return true;
+}
+
+bool DeviceManagerThread::RemoveSelectFd(Notifier* notify, int fd)
+{
+ // [0] is reserved for thread commands with notify of null, but we still
+ // can use this function to remove it.
+ for (UPInt i = 0; i < FdNotifiers.GetSize(); i++)
+ {
+ if ((FdNotifiers[i] == notify) && (PollFds[i].fd == fd))
+ {
+ FdNotifiers.RemoveAt(i);
+ PollFds.RemoveAt(i);
+ return true;
+ }
+ }
+ return false;
+}
+
+
+
+int DeviceManagerThread::Run()
+{
+ ThreadCommand::PopBuffer command;
+
+ SetThreadName("OVR::DeviceManagerThread");
+ LogText("OVR::DeviceManagerThread - running (ThreadId=%p).\n", GetThreadId());
+
+ // Signal to the parent thread that initialization has finished.
+ StartupEvent.SetEvent();
+
+ while(!IsExiting())
+ {
+ // PopCommand will reset event on empty queue.
+ if (PopCommand(&command))
+ {
+ command.Execute();
+ }
+ else
+ {
+ bool commands = 0;
+ do
+ {
+ int waitMs = -1;
+
+ // If devices have time-dependent logic registered, get the longest wait
+ // allowed based on current ticks.
+ if (!TicksNotifiers.IsEmpty())
+ {
+ UInt64 ticksMks = Timer::GetTicks();
+ int waitAllowed;
+
+ for (UPInt j = 0; j < TicksNotifiers.GetSize(); j++)
+ {
+ waitAllowed = (int)(TicksNotifiers[j]->OnTicks(ticksMks) / Timer::MksPerMs);
+ if (waitAllowed < waitMs)
+ waitMs = waitAllowed;
+ }
+ }
+
+ // wait until there is data available on one of the devices or the timeout expires
+ int n = poll(&PollFds[0], PollFds.GetSize(), waitMs);
+
+ if (n > 0)
+ {
+ // Iterate backwards through the list so the ordering will not be
+ // affected if the called object gets removed during the callback
+ // Also, the HID data streams are located toward the back of the list
+ // and servicing them first will allow a disconnect to be handled
+ // and cleaned directly at the device first instead of the general HID monitor
+ for (int i=PollFds.GetSize()-1; i>=0; i--)
+ {
+ if (PollFds[i].revents & POLLERR)
+ {
+ OVR_DEBUG_LOG(("poll: error on [%d]: %d", i, PollFds[i].fd));
+ }
+ else if (PollFds[i].revents & POLLIN)
+ {
+ if (FdNotifiers[i])
+ FdNotifiers[i]->OnEvent(i, PollFds[i].fd);
+ else if (i == 0) // command
+ {
+ char dummy[128];
+ read(PollFds[i].fd, dummy, 128);
+ commands = 1;
+ }
+ }
+
+ if (PollFds[i].revents & POLLHUP)
+ PollFds[i].events = 0;
+
+ if (PollFds[i].revents != 0)
+ {
+ n--;
+ if (n == 0)
+ break;
+ }
+ }
+ }
+ } while (PollFds.GetSize() > 0 && !commands);
+ }
+ }
+
+ LogText("OVR::DeviceManagerThread - exiting (ThreadId=%p).\n", GetThreadId());
+ return 0;
+}
+
+bool DeviceManagerThread::AddTicksNotifier(Notifier* notify)
+{
+ TicksNotifiers.PushBack(notify);
+ return true;
+}
+
+bool DeviceManagerThread::RemoveTicksNotifier(Notifier* notify)
+{
+ for (UPInt i = 0; i < TicksNotifiers.GetSize(); i++)
+ {
+ if (TicksNotifiers[i] == notify)
+ {
+ TicksNotifiers.RemoveAt(i);
+ return true;
+ }
+ }
+ return false;
+}
+
+} // namespace Linux
+
+
+//-------------------------------------------------------------------------------------
+// ***** Creation
+
+
+// Creates a new DeviceManager and initializes OVR.
+DeviceManager* DeviceManager::Create()
+{
+ if (!System::IsInitialized())
+ {
+ // Use custom message, since Log is not yet installed.
+ OVR_DEBUG_STATEMENT(Log::GetDefaultLog()->
+ LogMessage(Log_Debug, "DeviceManager::Create failed - OVR::System not initialized"); );
+ return 0;
+ }
+
+ Ptr<Linux::DeviceManager> manager = *new Linux::DeviceManager;
+
+ if (manager)
+ {
+ if (manager->Initialize(0))
+ {
+ manager->AddFactory(&LatencyTestDeviceFactory::Instance);
+ manager->AddFactory(&SensorDeviceFactory::Instance);
+ manager->AddFactory(&Linux::HMDDeviceFactory::Instance);
+
+ manager->AddRef();
+ }
+ else
+ {
+ manager.Clear();
+ }
+
+ }
+
+ return manager.GetPtr();
+}
+
+
+} // namespace OVR
+
diff --git a/LibOVR/Src/OVR_Linux_DeviceManager.h b/LibOVR/Src/OVR_Linux_DeviceManager.h
new file mode 100644
index 0000000..69dabc0
--- /dev/null
+++ b/LibOVR/Src/OVR_Linux_DeviceManager.h
@@ -0,0 +1,111 @@
+/************************************************************************************
+
+Filename : OVR_Linux_DeviceManager.h
+Content : Linux-specific DeviceManager header.
+Created :
+Authors :
+
+Copyright : Copyright 2012 Oculus VR, Inc. All Rights reserved.
+
+Use of this software is subject to the terms of the Oculus license
+agreement provided at the time of installation or download, or which
+otherwise accompanies this software in either electronic or hard copy form.
+
+*************************************************************************************/
+
+#ifndef OVR_Linux_DeviceManager_h
+#define OVR_Linux_DeviceManager_h
+
+#include "OVR_DeviceImpl.h"
+
+#include <unistd.h>
+#include <sys/poll.h>
+
+
+namespace OVR { namespace Linux {
+
+class DeviceManagerThread;
+
+//-------------------------------------------------------------------------------------
+// ***** Linux DeviceManager
+
+class DeviceManager : public DeviceManagerImpl
+{
+public:
+ DeviceManager();
+ ~DeviceManager();
+
+ // Initialize/Shutdowncreate and shutdown manger thread.
+ virtual bool Initialize(DeviceBase* parent);
+ virtual void Shutdown();
+
+ virtual ThreadCommandQueue* GetThreadQueue();
+ virtual ThreadId GetThreadId() const;
+
+ virtual DeviceEnumerator<> EnumerateDevicesEx(const DeviceEnumerationArgs& args);
+
+ virtual bool GetDeviceInfo(DeviceInfo* info) const;
+
+ Ptr<DeviceManagerThread> pThread;
+};
+
+//-------------------------------------------------------------------------------------
+// ***** Device Manager Background Thread
+
+class DeviceManagerThread : public Thread, public ThreadCommandQueue
+{
+ friend class DeviceManager;
+ enum { ThreadStackSize = 64 * 1024 };
+public:
+ DeviceManagerThread();
+ ~DeviceManagerThread();
+
+ virtual int Run();
+
+ // ThreadCommandQueue notifications for CommandEvent handling.
+ virtual void OnPushNonEmpty_Locked() { write(CommandFd[1], this, 1); }
+ virtual void OnPopEmpty_Locked() { }
+
+ class Notifier
+ {
+ public:
+ // Called when I/O is received
+ virtual void OnEvent(int i, int fd) = 0;
+
+ // Called when timing ticks are updated.
+ // Returns the largest number of microseconds this function can
+ // wait till next call.
+ virtual UInt64 OnTicks(UInt64 ticksMks)
+ {
+ OVR_UNUSED1(ticksMks);
+ return Timer::MksPerSecond * 1000;
+ }
+ };
+
+ // Add I/O notifier
+ bool AddSelectFd(Notifier* notify, int fd);
+ bool RemoveSelectFd(Notifier* notify, int fd);
+
+ // Add notifier that will be called at regular intervals.
+ bool AddTicksNotifier(Notifier* notify);
+ bool RemoveTicksNotifier(Notifier* notify);
+
+private:
+
+ bool threadInitialized() { return CommandFd[0] != 0; }
+
+ // pipe used to signal commands
+ int CommandFd[2];
+
+ Array<struct pollfd> PollFds;
+ Array<Notifier*> FdNotifiers;
+
+ Event StartupEvent;
+
+ // Ticks notifiers - used for time-dependent events such as keep-alive.
+ Array<Notifier*> TicksNotifiers;
+};
+
+}} // namespace Linux::OVR
+
+#endif // OVR_Linux_DeviceManager_h
diff --git a/LibOVR/Src/OVR_Linux_HIDDevice.cpp b/LibOVR/Src/OVR_Linux_HIDDevice.cpp
new file mode 100644
index 0000000..6656e9a
--- /dev/null
+++ b/LibOVR/Src/OVR_Linux_HIDDevice.cpp
@@ -0,0 +1,799 @@
+/************************************************************************************
+Filename : OVR_Linux_HIDDevice.cpp
+Content : Linux HID device implementation.
+Created : February 26, 2013
+Authors : Lee Cooper
+
+Copyright : Copyright 2013 Oculus VR, Inc. All Rights reserved.
+
+Use of this software is subject to the terms of the Oculus license
+agreement provided at the time of installation or download, or which
+otherwise accompanies this software in either electronic or hard copy form.
+
+*************************************************************************************/
+
+#include "OVR_Linux_HIDDevice.h"
+
+#include <sys/ioctl.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <linux/hidraw.h>
+#include "OVR_HIDDeviceImpl.h"
+
+namespace OVR { namespace Linux {
+
+static const UInt32 MAX_QUEUED_INPUT_REPORTS = 5;
+
+//-------------------------------------------------------------------------------------
+// **** Linux::DeviceManager
+//-----------------------------------------------------------------------------
+HIDDeviceManager::HIDDeviceManager(DeviceManager* manager) : DevManager(manager)
+{
+ UdevInstance = NULL;
+ HIDMonitor = NULL;
+ HIDMonHandle = -1;
+}
+
+//-----------------------------------------------------------------------------
+HIDDeviceManager::~HIDDeviceManager()
+{
+}
+
+//-----------------------------------------------------------------------------
+bool HIDDeviceManager::initializeManager()
+{
+ if (HIDMonitor)
+ {
+ return true;
+ }
+
+ // Create a udev_monitor handle to watch for device changes (hot-plug detection)
+ HIDMonitor = udev_monitor_new_from_netlink(UdevInstance, "udev");
+ if (HIDMonitor == NULL)
+ {
+ return false;
+ }
+
+ udev_monitor_filter_add_match_subsystem_devtype(HIDMonitor, "hidraw", NULL); // filter for hidraw only
+
+ int err = udev_monitor_enable_receiving(HIDMonitor);
+ if (err)
+ {
+ udev_monitor_unref(HIDMonitor);
+ HIDMonitor = NULL;
+ return false;
+ }
+
+ // Get the file descriptor (fd) for the monitor.
+ HIDMonHandle = udev_monitor_get_fd(HIDMonitor);
+ if (HIDMonHandle < 0)
+ {
+ udev_monitor_unref(HIDMonitor);
+ HIDMonitor = NULL;
+ return false;
+ }
+
+ // This file handle will be polled along-side with the device hid handles for changes
+ // Add the handle to the polling list
+ if (!DevManager->pThread->AddSelectFd(this, HIDMonHandle))
+ {
+ close(HIDMonHandle);
+ HIDMonHandle = -1;
+
+ udev_monitor_unref(HIDMonitor);
+ HIDMonitor = NULL;
+ return false;
+ }
+
+ return true;
+}
+
+//-----------------------------------------------------------------------------
+bool HIDDeviceManager::Initialize()
+{
+ // Get a udev library handle. This handle must stay active during the
+ // duration the lifetime of device monitoring handles
+ UdevInstance = udev_new();
+ if (!UdevInstance)
+ return false;
+
+ return initializeManager();
+}
+
+//-----------------------------------------------------------------------------
+void HIDDeviceManager::Shutdown()
+{
+ OVR_ASSERT_LOG((UdevInstance), ("Should have called 'Initialize' before 'Shutdown'."));
+
+ if (HIDMonitor)
+ {
+ DevManager->pThread->RemoveSelectFd(this, HIDMonHandle);
+ close(HIDMonHandle);
+ HIDMonHandle = -1;
+
+ udev_monitor_unref(HIDMonitor);
+ HIDMonitor = NULL;
+ }
+
+ udev_unref(UdevInstance); // release the library
+
+ LogText("OVR::Linux::HIDDeviceManager - shutting down.\n");
+}
+
+//-------------------------------------------------------------------------------
+bool HIDDeviceManager::AddNotificationDevice(HIDDevice* device)
+{
+ NotificationDevices.PushBack(device);
+ return true;
+}
+
+//-------------------------------------------------------------------------------
+bool HIDDeviceManager::RemoveNotificationDevice(HIDDevice* device)
+{
+ for (UPInt i = 0; i < NotificationDevices.GetSize(); i++)
+ {
+ if (NotificationDevices[i] == device)
+ {
+ NotificationDevices.RemoveAt(i);
+ return true;
+ }
+ }
+ return false;
+}
+
+//-----------------------------------------------------------------------------
+bool HIDDeviceManager::getIntProperty(udev_device* device,
+ const char* propertyName,
+ SInt32* pResult)
+{
+ const char* str = udev_device_get_sysattr_value(device, propertyName);
+ if (str)
+ {
+ *pResult = strtol(str, NULL, 16);
+ return true;
+ }
+ else
+ {
+ *pResult = 0;
+ return true;
+ }
+}
+
+//-----------------------------------------------------------------------------
+bool HIDDeviceManager::initVendorProductVersion(udev_device* device, HIDDeviceDesc* pDevDesc)
+{
+ SInt32 result;
+ if (getIntProperty(device, "idVendor", &result))
+ pDevDesc->VendorId = result;
+ else
+ return false;
+
+ if (getIntProperty(device, "idProduct", &result))
+ pDevDesc->ProductId = result;
+ else
+ return false;
+
+ return true;
+}
+
+//-----------------------------------------------------------------------------
+bool HIDDeviceManager::getStringProperty(udev_device* device,
+ const char* propertyName,
+ OVR::String* pResult)
+{
+ // Get the attribute in UTF8
+ const char* str = udev_device_get_sysattr_value(device, propertyName);
+ if (str)
+ { // Copy the string into the return value
+ *pResult = String(str);
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+}
+
+//-----------------------------------------------------------------------------
+bool HIDDeviceManager::Enumerate(HIDEnumerateVisitor* enumVisitor)
+{
+
+ if (!initializeManager())
+ {
+ return false;
+ }
+
+ // Get a list of hid devices
+ udev_enumerate* devices = udev_enumerate_new(UdevInstance);
+ udev_enumerate_add_match_subsystem(devices, "hidraw");
+ udev_enumerate_scan_devices(devices);
+
+ udev_list_entry* entry = udev_enumerate_get_list_entry(devices);
+
+ // Search each device for the matching vid/pid
+ while (entry != NULL)
+ {
+ // Get the device file name
+ const char* sysfs_path = udev_list_entry_get_name(entry);
+ udev_device* hid; // The device's HID udev node.
+ hid = udev_device_new_from_syspath(UdevInstance, sysfs_path);
+ const char* dev_path = udev_device_get_devnode(hid);
+
+ // Get the USB device
+ hid = udev_device_get_parent_with_subsystem_devtype(hid, "usb", "usb_device");
+ if (hid)
+ {
+ HIDDeviceDesc devDesc;
+
+ // Check the VID/PID for a match
+ if (dev_path &&
+ initVendorProductVersion(hid, &devDesc) &&
+ enumVisitor->MatchVendorProduct(devDesc.VendorId, devDesc.ProductId))
+ {
+ devDesc.Path = dev_path;
+ getFullDesc(hid, &devDesc);
+
+ // Look for the device to check if it is already opened.
+ Ptr<DeviceCreateDesc> existingDevice = DevManager->FindHIDDevice(devDesc);
+ // if device exists and it is opened then most likely the device open()
+ // will fail; therefore, we just set Enumerated to 'true' and continue.
+ if (existingDevice && existingDevice->pDevice)
+ {
+ existingDevice->Enumerated = true;
+ }
+ else
+ { // open the device temporarily for startup communication
+ int device_handle = open(dev_path, O_RDWR);
+ if (device_handle >= 0)
+ {
+ // Construct minimal device that the visitor callback can get feature reports from
+ Linux::HIDDevice device(this, device_handle);
+ enumVisitor->Visit(device, devDesc);
+
+ close(device_handle); // close the file handle
+ }
+ }
+ }
+
+ udev_device_unref(hid);
+ entry = udev_list_entry_get_next(entry);
+ }
+ }
+
+ // Free the enumerator and udev objects
+ udev_enumerate_unref(devices);
+
+ return true;
+}
+
+//-----------------------------------------------------------------------------
+OVR::HIDDevice* HIDDeviceManager::Open(const String& path)
+{
+ Ptr<Linux::HIDDevice> device = *new Linux::HIDDevice(this);
+
+ if (device->HIDInitialize(path))
+ {
+ device->AddRef();
+ return device;
+ }
+
+ return NULL;
+}
+
+//-----------------------------------------------------------------------------
+bool HIDDeviceManager::getFullDesc(udev_device* device, HIDDeviceDesc* desc)
+{
+
+ if (!initVendorProductVersion(device, desc))
+ {
+ return false;
+ }
+
+ if (!getStringProperty(device, "serial", &(desc->SerialNumber)))
+ {
+ return false;
+ }
+
+ getStringProperty(device, "manufacturer", &(desc->Manufacturer));
+ getStringProperty(device, "product", &(desc->Product));
+
+ return true;
+}
+
+//-----------------------------------------------------------------------------
+bool HIDDeviceManager::GetDescriptorFromPath(const char* dev_path, HIDDeviceDesc* desc)
+{
+ if (!initializeManager())
+ {
+ return false;
+ }
+
+ // Search for the udev device from the given pathname so we can
+ // have a handle to query device properties
+
+ udev_enumerate* devices = udev_enumerate_new(UdevInstance);
+ udev_enumerate_add_match_subsystem(devices, "hidraw");
+ udev_enumerate_scan_devices(devices);
+
+ udev_list_entry* entry = udev_enumerate_get_list_entry(devices);
+
+ bool success = false;
+ // Search for the device with the matching path
+ while (entry != NULL)
+ {
+ // Get the device file name
+ const char* sysfs_path = udev_list_entry_get_name(entry);
+ udev_device* hid; // The device's HID udev node.
+ hid = udev_device_new_from_syspath(UdevInstance, sysfs_path);
+ const char* path = udev_device_get_devnode(hid);
+
+ if (OVR_strcmp(dev_path, path) == 0)
+ { // Found the device so lets collect the device descriptor
+
+ // Get the USB device
+ hid = udev_device_get_parent_with_subsystem_devtype(hid, "usb", "usb_device");
+ if (hid)
+ {
+ desc->Path = dev_path;
+ success = getFullDesc(hid, desc);
+ }
+
+ }
+
+ udev_device_unref(hid);
+ entry = udev_list_entry_get_next(entry);
+ }
+
+ // Free the enumerator
+ udev_enumerate_unref(devices);
+
+ return success;
+}
+
+//-----------------------------------------------------------------------------
+void HIDDeviceManager::OnEvent(int i, int fd)
+{
+ // There is a device status change
+ udev_device* hid = udev_monitor_receive_device(HIDMonitor);
+ if (hid)
+ {
+ const char* dev_path = udev_device_get_devnode(hid);
+ const char* action = udev_device_get_action(hid);
+
+ HIDDeviceDesc device_info;
+ device_info.Path = dev_path;
+
+ MessageType notify_type;
+ if (OVR_strcmp(action, "add") == 0)
+ {
+ notify_type = Message_DeviceAdded;
+
+ // Retrieve the device info. This can only be done on a connected
+ // device and is invalid for a disconnected device
+
+ // Get the USB device
+ hid = udev_device_get_parent_with_subsystem_devtype(hid, "usb", "usb_device");
+ if (!hid)
+ {
+ return;
+ }
+
+ getFullDesc(hid, &device_info);
+ }
+ else if (OVR_strcmp(action, "remove") == 0)
+ {
+ notify_type = Message_DeviceRemoved;
+ }
+ else
+ {
+ return;
+ }
+
+ bool error = false;
+ bool deviceFound = false;
+ for (UPInt i = 0; i < NotificationDevices.GetSize(); i++)
+ {
+ if (NotificationDevices[i] &&
+ NotificationDevices[i]->OnDeviceNotification(notify_type, &device_info, &error))
+ {
+ // The notification was for an existing device
+ deviceFound = true;
+ break;
+ }
+ }
+
+ if (notify_type == Message_DeviceAdded && !deviceFound)
+ {
+ DevManager->DetectHIDDevice(device_info);
+ }
+
+ udev_device_unref(hid);
+ }
+}
+
+//=============================================================================
+// Linux::HIDDevice
+//=============================================================================
+HIDDevice::HIDDevice(HIDDeviceManager* manager)
+ : HIDManager(manager), InMinimalMode(false)
+{
+ DeviceHandle = -1;
+}
+
+//-----------------------------------------------------------------------------
+// This is a minimal constructor used during enumeration for us to pass
+// a HIDDevice to the visit function (so that it can query feature reports).
+HIDDevice::HIDDevice(HIDDeviceManager* manager, int device_handle)
+: HIDManager(manager), DeviceHandle(device_handle), InMinimalMode(true)
+{
+}
+
+//-----------------------------------------------------------------------------
+HIDDevice::~HIDDevice()
+{
+ if (!InMinimalMode)
+ {
+ HIDShutdown();
+ }
+}
+
+//-----------------------------------------------------------------------------
+bool HIDDevice::HIDInitialize(const String& path)
+{
+ const char* hid_path = path.ToCStr();
+ if (!openDevice(hid_path))
+ {
+ LogText("OVR::Linux::HIDDevice - Failed to open HIDDevice: %s", hid_path);
+ return false;
+ }
+
+ HIDManager->DevManager->pThread->AddTicksNotifier(this);
+ HIDManager->AddNotificationDevice(this);
+
+ LogText("OVR::Linux::HIDDevice - Opened '%s'\n"
+ " Manufacturer:'%s' Product:'%s' Serial#:'%s'\n",
+ DevDesc.Path.ToCStr(),
+ DevDesc.Manufacturer.ToCStr(), DevDesc.Product.ToCStr(),
+ DevDesc.SerialNumber.ToCStr());
+
+ return true;
+}
+
+//-----------------------------------------------------------------------------
+bool HIDDevice::initInfo()
+{
+ // Device must have been successfully opened.
+ OVR_ASSERT(DeviceHandle >= 0);
+
+ int desc_size = 0;
+ hidraw_report_descriptor rpt_desc;
+ memset(&rpt_desc, 0, sizeof(rpt_desc));
+
+ // get report descriptor size
+ int r = ioctl(DeviceHandle, HIDIOCGRDESCSIZE, &desc_size);
+ if (r < 0)
+ {
+ OVR_ASSERT_LOG(false, ("Failed to get report descriptor size."));
+ return false;
+ }
+
+ // Get the report descriptor
+ rpt_desc.size = desc_size;
+ r = ioctl(DeviceHandle, HIDIOCGRDESC, &rpt_desc);
+ if (r < 0)
+ {
+ OVR_ASSERT_LOG(false, ("Failed to get report descriptor."));
+ return false;
+ }
+
+ /*
+ // Get report lengths.
+ SInt32 bufferLength;
+ bool getResult = HIDManager->getIntProperty(Device, CFSTR(kIOHIDMaxInputReportSizeKey), &bufferLength);
+ OVR_ASSERT(getResult);
+ InputReportBufferLength = (UInt16) bufferLength;
+
+ getResult = HIDManager->getIntProperty(Device, CFSTR(kIOHIDMaxOutputReportSizeKey), &bufferLength);
+ OVR_ASSERT(getResult);
+ OutputReportBufferLength = (UInt16) bufferLength;
+
+ getResult = HIDManager->getIntProperty(Device, CFSTR(kIOHIDMaxFeatureReportSizeKey), &bufferLength);
+ OVR_ASSERT(getResult);
+ FeatureReportBufferLength = (UInt16) bufferLength;
+
+
+ if (ReadBufferSize < InputReportBufferLength)
+ {
+ OVR_ASSERT_LOG(false, ("Input report buffer length is bigger than read buffer."));
+ return false;
+ }
+
+ // Get device desc.
+ if (!HIDManager->getFullDesc(Device, &DevDesc))
+ {
+ OVR_ASSERT_LOG(false, ("Failed to get device desc while initializing device."));
+ return false;
+ }
+
+ return true;
+ */
+
+ // Get report lengths.
+// TODO: hard-coded for now. Need to interpret these values from the report descriptor
+ InputReportBufferLength = 62;
+ OutputReportBufferLength = 0;
+ FeatureReportBufferLength = 69;
+
+ if (ReadBufferSize < InputReportBufferLength)
+ {
+ OVR_ASSERT_LOG(false, ("Input report buffer length is bigger than read buffer."));
+ return false;
+ }
+
+ return true;
+}
+
+//-----------------------------------------------------------------------------
+bool HIDDevice::openDevice(const char* device_path)
+{
+ // First fill out the device descriptor
+ if (!HIDManager->GetDescriptorFromPath(device_path, &DevDesc))
+ {
+ return false;
+ }
+
+ // Now open the device
+ DeviceHandle = open(device_path, O_RDWR);
+ if (DeviceHandle < 0)
+ {
+ OVR_DEBUG_LOG(("Failed 'CreateHIDFile' while opening device, error = 0x%X.", errno));
+ DeviceHandle = -1;
+ return false;
+ }
+
+ // fill out some values from the feature report descriptor
+ if (!initInfo())
+ {
+ OVR_ASSERT_LOG(false, ("Failed to get HIDDevice info."));
+
+ close(DeviceHandle);
+ DeviceHandle = -1;
+ return false;
+ }
+
+ // Add the device to the polling list
+ if (!HIDManager->DevManager->pThread->AddSelectFd(this, DeviceHandle))
+ {
+ OVR_ASSERT_LOG(false, ("Failed to initialize polling for HIDDevice."));
+
+ close(DeviceHandle);
+ DeviceHandle = -1;
+ return false;
+ }
+
+ return true;
+}
+
+//-----------------------------------------------------------------------------
+void HIDDevice::HIDShutdown()
+{
+
+ HIDManager->DevManager->pThread->RemoveTicksNotifier(this);
+ HIDManager->RemoveNotificationDevice(this);
+
+ if (DeviceHandle >= 0) // Device may already have been closed if unplugged.
+ {
+ closeDevice(false);
+ }
+
+ LogText("OVR::Linux::HIDDevice - HIDShutdown '%s'\n", DevDesc.Path.ToCStr());
+}
+
+//-----------------------------------------------------------------------------
+void HIDDevice::closeDevice(bool wasUnplugged)
+{
+ OVR_ASSERT(DeviceHandle >= 0);
+
+
+ HIDManager->DevManager->pThread->RemoveSelectFd(this, DeviceHandle);
+
+ close(DeviceHandle); // close the file handle
+ DeviceHandle = -1;
+
+ LogText("OVR::Linux::HIDDevice - HID Device Closed '%s'\n", DevDesc.Path.ToCStr());
+}
+
+//-----------------------------------------------------------------------------
+void HIDDevice::closeDeviceOnIOError()
+{
+ LogText("OVR::Linux::HIDDevice - Lost connection to '%s'\n", DevDesc.Path.ToCStr());
+ closeDevice(false);
+}
+
+//-----------------------------------------------------------------------------
+bool HIDDevice::SetFeatureReport(UByte* data, UInt32 length)
+{
+
+ if (DeviceHandle < 0)
+ return false;
+
+ UByte reportID = data[0];
+
+ if (reportID == 0)
+ {
+ // Not using reports so remove from data packet.
+ data++;
+ length--;
+ }
+
+ int r = ioctl(DeviceHandle, HIDIOCSFEATURE(length), data);
+ return (r >= 0);
+}
+
+//-----------------------------------------------------------------------------
+bool HIDDevice::GetFeatureReport(UByte* data, UInt32 length)
+{
+ if (DeviceHandle < 0)
+ return false;
+
+ int r = ioctl(DeviceHandle, HIDIOCGFEATURE(length), data);
+ return (r >= 0);
+}
+
+//-----------------------------------------------------------------------------
+UInt64 HIDDevice::OnTicks(UInt64 ticksMks)
+{
+ if (Handler)
+ {
+ return Handler->OnTicks(ticksMks);
+ }
+
+ return DeviceManagerThread::Notifier::OnTicks(ticksMks);
+}
+
+//-----------------------------------------------------------------------------
+void HIDDevice::OnEvent(int i, int fd)
+{
+ // We have data to read from the device
+ int bytes = read(fd, ReadBuffer, ReadBufferSize);
+ if (bytes >= 0)
+ {
+// TODO: I need to handle partial messages and package reconstruction
+ if (Handler)
+ {
+ Handler->OnInputReport(ReadBuffer, bytes);
+ }
+ }
+ else
+ { // Close the device on read error.
+ closeDeviceOnIOError();
+ }
+}
+
+//-----------------------------------------------------------------------------
+bool HIDDevice::OnDeviceNotification(MessageType messageType,
+ HIDDeviceDesc* device_info,
+ bool* error)
+{
+ const char* device_path = device_info->Path.ToCStr();
+
+ if (messageType == Message_DeviceAdded && DeviceHandle < 0)
+ {
+ // Is this the correct device?
+ if (!(device_info->VendorId == DevDesc.VendorId
+ && device_info->ProductId == DevDesc.ProductId
+ && device_info->SerialNumber == DevDesc.SerialNumber))
+ {
+ return false;
+ }
+
+ // A closed device has been re-added. Try to reopen.
+ if (!openDevice(device_path))
+ {
+ LogError("OVR::Linux::HIDDevice - Failed to reopen a device '%s' that was re-added.\n",
+ device_path);
+ *error = true;
+ return true;
+ }
+
+ LogText("OVR::Linux::HIDDevice - Reopened device '%s'\n", device_path);
+
+ if (Handler)
+ {
+ Handler->OnDeviceMessage(HIDHandler::HIDDeviceMessage_DeviceAdded);
+ }
+ }
+ else if (messageType == Message_DeviceRemoved)
+ {
+ // Is this the correct device?
+ // For disconnected device, the device description will be invalid so
+ // checking the path is the only way to match them
+ if (DevDesc.Path.CompareNoCase(device_path) != 0)
+ {
+ return false;
+ }
+
+ if (DeviceHandle >= 0)
+ {
+ closeDevice(true);
+ }
+
+ if (Handler)
+ {
+ Handler->OnDeviceMessage(HIDHandler::HIDDeviceMessage_DeviceRemoved);
+ }
+ }
+ else
+ {
+ OVR_ASSERT(0);
+ }
+
+ *error = false;
+ return true;
+}
+
+//-----------------------------------------------------------------------------
+HIDDeviceManager* HIDDeviceManager::CreateInternal(Linux::DeviceManager* devManager)
+{
+
+ if (!System::IsInitialized())
+ {
+ // Use custom message, since Log is not yet installed.
+ OVR_DEBUG_STATEMENT(Log::GetDefaultLog()->
+ LogMessage(Log_Debug, "HIDDeviceManager::Create failed - OVR::System not initialized"); );
+ return 0;
+ }
+
+ Ptr<Linux::HIDDeviceManager> manager = *new Linux::HIDDeviceManager(devManager);
+
+ if (manager)
+ {
+ if (manager->Initialize())
+ {
+ manager->AddRef();
+ }
+ else
+ {
+ manager.Clear();
+ }
+ }
+
+ return manager.GetPtr();
+}
+
+} // namespace Linux
+
+//-------------------------------------------------------------------------------------
+// ***** Creation
+
+// Creates a new HIDDeviceManager and initializes OVR.
+HIDDeviceManager* HIDDeviceManager::Create()
+{
+ OVR_ASSERT_LOG(false, ("Standalone mode not implemented yet."));
+
+ if (!System::IsInitialized())
+ {
+ // Use custom message, since Log is not yet installed.
+ OVR_DEBUG_STATEMENT(Log::GetDefaultLog()->
+ LogMessage(Log_Debug, "HIDDeviceManager::Create failed - OVR::System not initialized"); );
+ return 0;
+ }
+
+ Ptr<Linux::HIDDeviceManager> manager = *new Linux::HIDDeviceManager(NULL);
+
+ if (manager)
+ {
+ if (manager->Initialize())
+ {
+ manager->AddRef();
+ }
+ else
+ {
+ manager.Clear();
+ }
+ }
+
+ return manager.GetPtr();
+}
+
+} // namespace OVR
diff --git a/LibOVR/Src/OVR_Linux_HIDDevice.h b/LibOVR/Src/OVR_Linux_HIDDevice.h
new file mode 100644
index 0000000..eae352e
--- /dev/null
+++ b/LibOVR/Src/OVR_Linux_HIDDevice.h
@@ -0,0 +1,124 @@
+/************************************************************************************
+Filename : OVR_Linux_HIDDevice.h
+Content : Linux HID device implementation.
+Created : June 13, 2013
+Authors : Brant Lewis
+
+Copyright : Copyright 2013 Oculus VR, Inc. All Rights reserved.
+
+Use of this software is subject to the terms of the Oculus license
+agreement provided at the time of installation or download, or which
+otherwise accompanies this software in either electronic or hard copy form.
+
+*************************************************************************************/
+
+#ifndef OVR_LINUX_HIDDevice_h
+#define OVR_LINUX_HIDDevice_h
+
+#include "OVR_HIDDevice.h"
+#include "OVR_Linux_DeviceManager.h"
+#include <libudev.h>
+
+namespace OVR { namespace Linux {
+
+class HIDDeviceManager;
+
+//-------------------------------------------------------------------------------------
+// ***** Linux HIDDevice
+
+class HIDDevice : public OVR::HIDDevice, public DeviceManagerThread::Notifier
+{
+private:
+ friend class HIDDeviceManager;
+
+public:
+ HIDDevice(HIDDeviceManager* manager);
+
+ // This is a minimal constructor used during enumeration for us to pass
+ // a HIDDevice to the visit function (so that it can query feature reports).
+ HIDDevice(HIDDeviceManager* manager, int device_handle);
+
+ virtual ~HIDDevice();
+
+ bool HIDInitialize(const String& path);
+ void HIDShutdown();
+
+ virtual bool SetFeatureReport(UByte* data, UInt32 length);
+ virtual bool GetFeatureReport(UByte* data, UInt32 length);
+
+ // DeviceManagerThread::Notifier
+ void OnEvent(int i, int fd);
+ UInt64 OnTicks(UInt64 ticksMks);
+
+ bool OnDeviceNotification(MessageType messageType,
+ HIDDeviceDesc* device_info,
+ bool* error);
+
+private:
+ bool initInfo();
+ bool openDevice(const char* dev_path);
+ void closeDevice(bool wasUnplugged);
+ void closeDeviceOnIOError();
+ bool setupDevicePluggedInNotification();
+
+ bool InMinimalMode;
+ HIDDeviceManager* HIDManager;
+ int DeviceHandle; // file handle to the device
+ HIDDeviceDesc DevDesc;
+
+ enum { ReadBufferSize = 96 };
+ UByte ReadBuffer[ReadBufferSize];
+
+ UInt16 InputReportBufferLength;
+ UInt16 OutputReportBufferLength;
+ UInt16 FeatureReportBufferLength;
+};
+
+
+//-------------------------------------------------------------------------------------
+// ***** Linux HIDDeviceManager
+
+class HIDDeviceManager : public OVR::HIDDeviceManager, public DeviceManagerThread::Notifier
+{
+ friend class HIDDevice;
+
+public:
+ HIDDeviceManager(Linux::DeviceManager* Manager);
+ virtual ~HIDDeviceManager();
+
+ virtual bool Initialize();
+ virtual void Shutdown();
+
+ virtual bool Enumerate(HIDEnumerateVisitor* enumVisitor);
+ virtual OVR::HIDDevice* Open(const String& path);
+
+ static HIDDeviceManager* CreateInternal(DeviceManager* manager);
+
+ void OnEvent(int i, int fd);
+
+private:
+ bool initializeManager();
+ bool initVendorProductVersion(udev_device* device, HIDDeviceDesc* pDevDesc);
+ bool getPath(udev_device* device, String* pPath);
+ bool getIntProperty(udev_device* device, const char* key, int32_t* pResult);
+ bool getStringProperty(udev_device* device,
+ const char* propertyName,
+ OVR::String* pResult);
+ bool getFullDesc(udev_device* device, HIDDeviceDesc* desc);
+ bool GetDescriptorFromPath(const char* dev_path, HIDDeviceDesc* desc);
+
+ bool AddNotificationDevice(HIDDevice* device);
+ bool RemoveNotificationDevice(HIDDevice* device);
+
+ DeviceManager* DevManager;
+
+ udev* UdevInstance; // a handle to the udev library instance
+ udev_monitor* HIDMonitor;
+ int HIDMonHandle; // the udev_monitor file handle
+
+ Array<HIDDevice*> NotificationDevices;
+};
+
+}} // namespace OVR::Linux
+
+#endif // OVR_Linux_HIDDevice_h
diff --git a/LibOVR/Src/OVR_Linux_HMDDevice.cpp b/LibOVR/Src/OVR_Linux_HMDDevice.cpp
new file mode 100644
index 0000000..7b26479
--- /dev/null
+++ b/LibOVR/Src/OVR_Linux_HMDDevice.cpp
@@ -0,0 +1,392 @@
+/************************************************************************************
+
+Filename : OVR_Linux_HMDDevice.h
+Content : Linux HMDDevice implementation
+Created : June 17, 2013
+Authors : Brant Lewis
+
+Copyright : Copyright 2013 Oculus VR, Inc. All Rights reserved.
+
+Use of this software is subject to the terms of the Oculus license
+agreement provided at the time of installation or download, or which
+otherwise accompanies this software in either electronic or hard copy form.
+
+*************************************************************************************/
+
+#include "OVR_Linux_HMDDevice.h"
+
+#include "OVR_Linux_DeviceManager.h"
+
+#include "OVR_Profile.h"
+
+#include <X11/Xlib.h>
+#include <X11/extensions/Xinerama.h>
+
+namespace OVR { namespace Linux {
+
+//-------------------------------------------------------------------------------------
+
+HMDDeviceCreateDesc::HMDDeviceCreateDesc(DeviceFactory* factory, const String& displayDeviceName, long dispId)
+ : DeviceCreateDesc(factory, Device_HMD),
+ DisplayDeviceName(displayDeviceName),
+ DesktopX(0), DesktopY(0), Contents(0),
+ HResolution(0), VResolution(0), HScreenSize(0), VScreenSize(0),
+ DisplayId(dispId)
+{
+ DeviceId = DisplayDeviceName;
+}
+
+HMDDeviceCreateDesc::HMDDeviceCreateDesc(const HMDDeviceCreateDesc& other)
+ : DeviceCreateDesc(other.pFactory, Device_HMD),
+ DeviceId(other.DeviceId), DisplayDeviceName(other.DisplayDeviceName),
+ DesktopX(other.DesktopX), DesktopY(other.DesktopY), Contents(other.Contents),
+ HResolution(other.HResolution), VResolution(other.VResolution),
+ HScreenSize(other.HScreenSize), VScreenSize(other.VScreenSize),
+ DisplayId(other.DisplayId)
+{
+}
+
+HMDDeviceCreateDesc::MatchResult HMDDeviceCreateDesc::MatchDevice(const DeviceCreateDesc& other,
+ DeviceCreateDesc** pcandidate) const
+{
+ if ((other.Type != Device_HMD) || (other.pFactory != pFactory))
+ return Match_None;
+
+ // There are several reasons we can come in here:
+ // a) Matching this HMD Monitor created desc to OTHER HMD Monitor desc
+ // - Require exact device DeviceId/DeviceName match
+ // b) Matching SensorDisplayInfo created desc to OTHER HMD Monitor desc
+ // - This DeviceId is empty; becomes candidate
+ // c) Matching this HMD Monitor created desc to SensorDisplayInfo desc
+ // - This other.DeviceId is empty; becomes candidate
+
+ const HMDDeviceCreateDesc& s2 = (const HMDDeviceCreateDesc&) other;
+
+ if ((DeviceId == s2.DeviceId) &&
+ (DisplayId == s2.DisplayId))
+ {
+ // Non-null DeviceId may match while size is different if screen size was overwritten
+ // by SensorDisplayInfo in prior iteration.
+ if (!DeviceId.IsEmpty() ||
+ ((HScreenSize == s2.HScreenSize) &&
+ (VScreenSize == s2.VScreenSize)) )
+ {
+ *pcandidate = 0;
+ return Match_Found;
+ }
+ }
+
+
+ // DisplayInfo takes precedence, although we try to match it first.
+ if ((HResolution == s2.HResolution) &&
+ (VResolution == s2.VResolution) &&
+ (HScreenSize == s2.HScreenSize) &&
+ (VScreenSize == s2.VScreenSize))
+ {
+ if (DeviceId.IsEmpty() && !s2.DeviceId.IsEmpty())
+ {
+ *pcandidate = const_cast<DeviceCreateDesc*>((const DeviceCreateDesc*)this);
+ return Match_Candidate;
+ }
+
+ *pcandidate = 0;
+ return Match_Found;
+ }
+
+ // SensorDisplayInfo may override resolution settings, so store as candidate.
+ if (s2.DeviceId.IsEmpty())
+ {
+ *pcandidate = const_cast<DeviceCreateDesc*>((const DeviceCreateDesc*)this);
+ return Match_Candidate;
+ }
+ // OTHER HMD Monitor desc may initialize DeviceName/Id
+ else if (DeviceId.IsEmpty())
+ {
+ *pcandidate = const_cast<DeviceCreateDesc*>((const DeviceCreateDesc*)this);
+ return Match_Candidate;
+ }
+
+ return Match_None;
+}
+
+
+bool HMDDeviceCreateDesc::UpdateMatchedCandidate(const DeviceCreateDesc& other,
+ bool* newDeviceFlag)
+{
+ // This candidate was the the "best fit" to apply sensor DisplayInfo to.
+ OVR_ASSERT(other.Type == Device_HMD);
+
+ const HMDDeviceCreateDesc& s2 = (const HMDDeviceCreateDesc&) other;
+
+ // Force screen size on resolution from SensorDisplayInfo.
+ // We do this because USB detection is more reliable as compared to HDMI EDID,
+ // which may be corrupted by splitter reporting wrong monitor
+ if (s2.DeviceId.IsEmpty())
+ {
+ HScreenSize = s2.HScreenSize;
+ VScreenSize = s2.VScreenSize;
+ Contents |= Contents_Screen;
+
+ if (s2.Contents & HMDDeviceCreateDesc::Contents_Distortion)
+ {
+ memcpy(DistortionK, s2.DistortionK, sizeof(float)*4);
+ Contents |= Contents_Distortion;
+ }
+ DeviceId = s2.DeviceId;
+ DisplayId = s2.DisplayId;
+ DisplayDeviceName = s2.DisplayDeviceName;
+ if (newDeviceFlag) *newDeviceFlag = true;
+ }
+ else if (DeviceId.IsEmpty())
+ {
+ DeviceId = s2.DeviceId;
+ DisplayId = s2.DisplayId;
+ DisplayDeviceName = s2.DisplayDeviceName;
+
+ // ScreenSize and Resolution are NOT assigned here, since they may have
+ // come from a sensor DisplayInfo (which has precedence over HDMI).
+
+ if (newDeviceFlag) *newDeviceFlag = true;
+ }
+ else
+ {
+ if (newDeviceFlag) *newDeviceFlag = false;
+ }
+
+ return true;
+}
+
+bool HMDDeviceCreateDesc::MatchDevice(const String& path)
+{
+ return DeviceId.CompareNoCase(path) == 0;
+}
+
+//-------------------------------------------------------------------------------------
+// ***** HMDDeviceFactory
+
+HMDDeviceFactory HMDDeviceFactory::Instance;
+
+void HMDDeviceFactory::EnumerateDevices(EnumerateVisitor& visitor)
+{
+ // For now we'll assume the Rift DK1 is attached in extended monitor mode. Ultimately we need to
+ // use XFree86 to enumerate X11 screens in case the Rift is attached as a separate screen. We also
+ // need to be able to read the EDID manufacturer product code to be able to differentiate between
+ // Rift models.
+
+ bool foundHMD = false;
+
+ Display* display = XOpenDisplay(NULL);
+ if (display)
+ {
+ int numberOfScreens;
+ XineramaScreenInfo* screens = XineramaQueryScreens(display, &numberOfScreens);
+
+ for (int i = 0; i < numberOfScreens; i++)
+ {
+ XineramaScreenInfo screenInfo = screens[i];
+
+ if (screenInfo.width == 1280 && screenInfo.height == 800)
+ {
+ String deviceName = "OVR0001";
+
+ HMDDeviceCreateDesc hmdCreateDesc(this, deviceName, i);
+ hmdCreateDesc.SetScreenParameters(screenInfo.x_org, screenInfo.y_org, 1280, 800, 0.14976f, 0.0936f);
+
+ OVR_DEBUG_LOG_TEXT(("DeviceManager - HMD Found %s - %d\n",
+ deviceName.ToCStr(), i));
+
+ // Notify caller about detected device. This will call EnumerateAddDevice
+ // if the this is the first time device was detected.
+ visitor.Visit(hmdCreateDesc);
+ foundHMD = true;
+ break;
+ }
+ }
+
+ XFree(screens);
+ }
+
+
+ // Real HMD device is not found; however, we still may have a 'fake' HMD
+ // device created via SensorDeviceImpl::EnumerateHMDFromSensorDisplayInfo.
+ // Need to find it and set 'Enumerated' to true to avoid Removal notification.
+ if (!foundHMD)
+ {
+ Ptr<DeviceCreateDesc> hmdDevDesc = getManager()->FindDevice("", Device_HMD);
+ if (hmdDevDesc)
+ hmdDevDesc->Enumerated = true;
+ }
+}
+
+DeviceBase* HMDDeviceCreateDesc::NewDeviceInstance()
+{
+ return new HMDDevice(this);
+}
+
+bool HMDDeviceCreateDesc::Is7Inch() const
+{
+ return (strstr(DeviceId.ToCStr(), "OVR0001") != 0) || (Contents & Contents_7Inch);
+}
+
+Profile* HMDDeviceCreateDesc::GetProfileAddRef() const
+{
+ // Create device may override profile name, so get it from there is possible.
+ ProfileManager* profileManager = GetManagerImpl()->GetProfileManager();
+ ProfileType profileType = GetProfileType();
+ const char * profileName = pDevice ?
+ ((HMDDevice*)pDevice)->GetProfileName() :
+ profileManager->GetDefaultProfileName(profileType);
+
+ return profileName ?
+ profileManager->LoadProfile(profileType, profileName) :
+ profileManager->GetDeviceDefaultProfile(profileType);
+}
+
+
+bool HMDDeviceCreateDesc::GetDeviceInfo(DeviceInfo* info) const
+{
+ if ((info->InfoClassType != Device_HMD) &&
+ (info->InfoClassType != Device_None))
+ return false;
+
+ bool is7Inch = Is7Inch();
+
+ OVR_strcpy(info->ProductName, DeviceInfo::MaxNameLength,
+ is7Inch ? "Oculus Rift DK1" :
+ ((HResolution >= 1920) ? "Oculus Rift DK HD" : "Oculus Rift DK1-Prototype") );
+ OVR_strcpy(info->Manufacturer, DeviceInfo::MaxNameLength, "Oculus VR");
+ info->Type = Device_HMD;
+ info->Version = 0;
+
+ // Display detection.
+ if (info->InfoClassType == Device_HMD)
+ {
+ HMDInfo* hmdInfo = static_cast<HMDInfo*>(info);
+
+ hmdInfo->DesktopX = DesktopX;
+ hmdInfo->DesktopY = DesktopY;
+ hmdInfo->HResolution = HResolution;
+ hmdInfo->VResolution = VResolution;
+ hmdInfo->HScreenSize = HScreenSize;
+ hmdInfo->VScreenSize = VScreenSize;
+ hmdInfo->VScreenCenter = VScreenSize * 0.5f;
+ hmdInfo->InterpupillaryDistance = 0.064f; // Default IPD; should be configurable.
+ hmdInfo->LensSeparationDistance = 0.0635f;
+
+ // Obtain IPD from profile.
+ Ptr<Profile> profile = *GetProfileAddRef();
+
+ if (profile)
+ {
+ hmdInfo->InterpupillaryDistance = profile->GetIPD();
+ // TBD: Switch on EyeCup type.
+ }
+
+ if (Contents & Contents_Distortion)
+ {
+ memcpy(hmdInfo->DistortionK, DistortionK, sizeof(float)*4);
+ }
+ else
+ {
+ if (is7Inch)
+ {
+ // 7" screen.
+ hmdInfo->DistortionK[0] = 1.0f;
+ hmdInfo->DistortionK[1] = 0.22f;
+ hmdInfo->DistortionK[2] = 0.24f;
+ hmdInfo->EyeToScreenDistance = 0.041f;
+ }
+ else
+ {
+ hmdInfo->DistortionK[0] = 1.0f;
+ hmdInfo->DistortionK[1] = 0.18f;
+ hmdInfo->DistortionK[2] = 0.115f;
+
+ if (HResolution == 1920)
+ hmdInfo->EyeToScreenDistance = 0.040f;
+ else
+ hmdInfo->EyeToScreenDistance = 0.0387f;
+ }
+
+ hmdInfo->ChromaAbCorrection[0] = 0.996f;
+ hmdInfo->ChromaAbCorrection[1] = -0.004f;
+ hmdInfo->ChromaAbCorrection[2] = 1.014f;
+ hmdInfo->ChromaAbCorrection[3] = 0.0f;
+ }
+
+ OVR_strcpy(hmdInfo->DisplayDeviceName, sizeof(hmdInfo->DisplayDeviceName),
+ DisplayDeviceName.ToCStr());
+ hmdInfo->DisplayId = DisplayId;
+ }
+
+ return true;
+}
+
+//-------------------------------------------------------------------------------------
+// ***** HMDDevice
+
+HMDDevice::HMDDevice(HMDDeviceCreateDesc* createDesc)
+ : OVR::DeviceImpl<OVR::HMDDevice>(createDesc, 0)
+{
+}
+HMDDevice::~HMDDevice()
+{
+}
+
+bool HMDDevice::Initialize(DeviceBase* parent)
+{
+ pParent = parent;
+
+ // Initialize user profile to default for device.
+ ProfileManager* profileManager = GetManager()->GetProfileManager();
+ ProfileName = profileManager->GetDefaultProfileName(getDesc()->GetProfileType());
+
+ return true;
+}
+void HMDDevice::Shutdown()
+{
+ ProfileName.Clear();
+ pCachedProfile.Clear();
+ pParent.Clear();
+}
+
+Profile* HMDDevice::GetProfile() const
+{
+ if (!pCachedProfile)
+ pCachedProfile = *getDesc()->GetProfileAddRef();
+ return pCachedProfile.GetPtr();
+}
+
+const char* HMDDevice::GetProfileName() const
+{
+ return ProfileName.ToCStr();
+}
+
+bool HMDDevice::SetProfileName(const char* name)
+{
+ pCachedProfile.Clear();
+ if (!name)
+ {
+ ProfileName.Clear();
+ return 0;
+ }
+ if (GetManager()->GetProfileManager()->HasProfile(getDesc()->GetProfileType(), name))
+ {
+ ProfileName = name;
+ return true;
+ }
+ return false;
+}
+
+OVR::SensorDevice* HMDDevice::GetSensor()
+{
+ // Just return first sensor found since we have no way to match it yet.
+ OVR::SensorDevice* sensor = GetManager()->EnumerateDevices<SensorDevice>().CreateDevice();
+ if (sensor)
+ sensor->SetCoordinateFrame(SensorDevice::Coord_HMD);
+ return sensor;
+}
+
+}} // namespace OVR::Linux
+
+
diff --git a/LibOVR/Src/OVR_Linux_HMDDevice.h b/LibOVR/Src/OVR_Linux_HMDDevice.h
new file mode 100644
index 0000000..d0585d1
--- /dev/null
+++ b/LibOVR/Src/OVR_Linux_HMDDevice.h
@@ -0,0 +1,156 @@
+/************************************************************************************
+
+Filename : OVR_Linux_HMDDevice.h
+Content : Linux HMDDevice implementation
+Created : June 17, 2013
+Authors : Brant Lewis
+
+Copyright : Copyright 2013 Oculus VR, Inc. All Rights reserved.
+
+Use of this software is subject to the terms of the Oculus license
+agreement provided at the time of installation or download, or which
+otherwise accompanies this software in either electronic or hard copy form.
+
+*************************************************************************************/
+
+#ifndef OVR_Linux_HMDDevice_h
+#define OVR_Linux_HMDDevice_h
+
+#include "OVR_Linux_DeviceManager.h"
+#include "OVR_Profile.h"
+
+namespace OVR { namespace Linux {
+
+class HMDDevice;
+
+//-------------------------------------------------------------------------------------
+
+// HMDDeviceFactory enumerates attached Oculus HMD devices.
+//
+// This is currently done by matching monitor device strings.
+
+class HMDDeviceFactory : public DeviceFactory
+{
+public:
+ static HMDDeviceFactory Instance;
+
+ // Enumerates devices, creating and destroying relevant objects in manager.
+ virtual void EnumerateDevices(EnumerateVisitor& visitor);
+
+protected:
+ DeviceManager* getManager() const { return (DeviceManager*) pManager; }
+};
+
+
+class HMDDeviceCreateDesc : public DeviceCreateDesc
+{
+ friend class HMDDevice;
+
+protected:
+ enum
+ {
+ Contents_Screen = 1,
+ Contents_Distortion = 2,
+ Contents_7Inch = 4,
+ };
+ String DeviceId;
+ String DisplayDeviceName;
+ int DesktopX, DesktopY;
+ unsigned Contents;
+ unsigned HResolution, VResolution;
+ float HScreenSize, VScreenSize;
+ long DisplayId;
+ float DistortionK[4];
+
+public:
+ HMDDeviceCreateDesc(DeviceFactory* factory, const String& displayDeviceName, long dispId);
+ HMDDeviceCreateDesc(const HMDDeviceCreateDesc& other);
+
+ virtual DeviceCreateDesc* Clone() const
+ {
+ return new HMDDeviceCreateDesc(*this);
+ }
+
+ virtual DeviceBase* NewDeviceInstance();
+
+ virtual MatchResult MatchDevice(const DeviceCreateDesc& other,
+ DeviceCreateDesc**) const;
+
+ // Matches device by path.
+ virtual bool MatchDevice(const String& path);
+
+ virtual bool UpdateMatchedCandidate(const DeviceCreateDesc&, bool* newDeviceFlag = NULL);
+
+ virtual bool GetDeviceInfo(DeviceInfo* info) const;
+
+ // Requests the currently used default profile. This profile affects the
+ // settings reported by HMDInfo.
+ Profile* GetProfileAddRef() const;
+
+ ProfileType GetProfileType() const
+ {
+ return (HResolution >= 1920) ? Profile_RiftDKHD : Profile_RiftDK1;
+ }
+
+
+ void SetScreenParameters(int x, int y, unsigned hres, unsigned vres, float hsize, float vsize)
+ {
+ DesktopX = x;
+ DesktopY = y;
+ HResolution = hres;
+ VResolution = vres;
+ HScreenSize = hsize;
+ VScreenSize = vsize;
+ Contents |= Contents_Screen;
+ }
+ void SetDistortion(const float* dks)
+ {
+ for (int i = 0; i < 4; i++)
+ DistortionK[i] = dks[i];
+ Contents |= Contents_Distortion;
+ }
+
+ void Set7Inch() { Contents |= Contents_7Inch; }
+
+ bool Is7Inch() const;
+};
+
+
+//-------------------------------------------------------------------------------------
+
+// HMDDevice represents an Oculus HMD device unit. An instance of this class
+// is typically created from the DeviceManager.
+// After HMD device is created, we its sensor data can be obtained by
+// first creating a Sensor object and then wrappig it in SensorFusion.
+
+class HMDDevice : public DeviceImpl<OVR::HMDDevice>
+{
+public:
+ HMDDevice(HMDDeviceCreateDesc* createDesc);
+ ~HMDDevice();
+
+ virtual bool Initialize(DeviceBase* parent);
+ virtual void Shutdown();
+
+ // Requests the currently used default profile. This profile affects the
+ // settings reported by HMDInfo.
+ virtual Profile* GetProfile() const;
+ virtual const char* GetProfileName() const;
+ virtual bool SetProfileName(const char* name);
+
+ // Query associated sensor.
+ virtual OVR::SensorDevice* GetSensor();
+
+protected:
+ HMDDeviceCreateDesc* getDesc() const { return (HMDDeviceCreateDesc*)pCreateDesc.GetPtr(); }
+
+ // User name for the profile used with this device.
+ String ProfileName;
+ mutable Ptr<Profile> pCachedProfile;
+};
+
+
+}} // namespace OVR::Linux
+
+#endif // OVR_Linux_HMDDevice_h
+
diff --git a/LibOVR/Src/OVR_Linux_SensorDevice.cpp b/LibOVR/Src/OVR_Linux_SensorDevice.cpp
new file mode 100644
index 0000000..d957ad5
--- /dev/null
+++ b/LibOVR/Src/OVR_Linux_SensorDevice.cpp
@@ -0,0 +1,48 @@
+/************************************************************************************
+
+Filename : OVR_Linux_SensorDevice.cpp
+Content : Linux SensorDevice implementation
+Created : June 13, 2013
+Authors : Brant Lewis
+
+Copyright : Copyright 2013 Oculus VR, Inc. All Rights reserved.
+
+Use of this software is subject to the terms of the Oculus license
+agreement provided at the time of installation or download, or which
+otherwise accompanies this software in either electronic or hard copy form.
+
+*************************************************************************************/
+
+//#include "OVR_OSX_HMDDevice.h"
+#include "OVR_SensorImpl.h"
+#include "OVR_DeviceImpl.h"
+
+namespace OVR { namespace OSX {
+
+} // namespace OSX
+
+//-------------------------------------------------------------------------------------
+void SensorDeviceImpl::EnumerateHMDFromSensorDisplayInfo( const SensorDisplayInfoImpl& displayInfo,
+ DeviceFactory::EnumerateVisitor& visitor)
+{
+/*
+ Linux::HMDDeviceCreateDesc hmdCreateDesc(&Linux::HMDDeviceFactory::Instance, 1, 1, "", 0);
+
+ hmdCreateDesc.SetScreenParameters( 0, 0,
+ displayInfo.HResolution, displayInfo.VResolution,
+ displayInfo.HScreenSize, displayInfo.VScreenSize);
+
+ if ((displayInfo.DistortionType & SensorDisplayInfoImpl::Mask_BaseFmt) == SensorDisplayInfoImpl::Base_Distortion)
+ hmdCreateDesc.SetDistortion(displayInfo.DistortionK);
+ if (displayInfo.HScreenSize > 0.14f)
+ hmdCreateDesc.Set7Inch();
+
+ visitor.Visit(hmdCreateDesc);
+ */
+
+
+}
+
+} // namespace OVR
+
+
diff --git a/LibOVR/Src/OVR_OSX_DeviceManager.cpp b/LibOVR/Src/OVR_OSX_DeviceManager.cpp
index b2403ed..90cfbfd 100644
--- a/LibOVR/Src/OVR_OSX_DeviceManager.cpp
+++ b/LibOVR/Src/OVR_OSX_DeviceManager.cpp
@@ -1,349 +1,349 @@
-/************************************************************************************
-
-Filename : OVR_OSX_DeviceManager.cpp
-Content : OSX specific DeviceManager implementation.
-Created : March 14, 2013
-Authors : Lee Cooper
-
-Copyright : Copyright 2013 Oculus VR, Inc. All Rights reserved.
-
-Use of this software is subject to the terms of the Oculus license
-agreement provided at the time of installation or download, or which
-otherwise accompanies this software in either electronic or hard copy form.
-
-*************************************************************************************/
-
-#include "OVR_OSX_DeviceManager.h"
-
-// Sensor & HMD Factories
-#include "OVR_LatencyTestImpl.h"
-#include "OVR_SensorImpl.h"
-#include "OVR_OSX_HMDDevice.h"
-#include "OVR_OSX_HIDDevice.h"
-
-#include "Kernel/OVR_Timer.h"
-#include "Kernel/OVR_Std.h"
-#include "Kernel/OVR_Log.h"
-
-#include <IOKit/hid/IOHIDManager.h>
-#include <IOKit/hid/IOHIDKeys.h>
-
-
-namespace OVR { namespace OSX {
-
-//-------------------------------------------------------------------------------------
-// **** OSX::DeviceManager
-
-DeviceManager::DeviceManager()
-{
-}
-
-DeviceManager::~DeviceManager()
-{
- OVR_DEBUG_LOG(("OSX::DeviceManager::~DeviceManager was called"));
-}
-
-bool DeviceManager::Initialize(DeviceBase*)
-{
- if (!DeviceManagerImpl::Initialize(0))
- return false;
-
- // Start the background thread.
- pThread = *new DeviceManagerThread();
- if (!pThread || !pThread->Start())
- return false;
-
- // Wait for the thread to be fully up and running.
- pThread->StartupEvent.Wait();
-
- // Do this now that we know the thread's run loop.
- HidDeviceManager = *HIDDeviceManager::CreateInternal(this);
-
- CGDisplayRegisterReconfigurationCallback(displayReconfigurationCallBack, this);
-
- pCreateDesc->pDevice = this;
- LogText("OVR::DeviceManager - initialized.\n");
-
- return true;
-}
-
-void DeviceManager::Shutdown()
-{
- LogText("OVR::DeviceManager - shutting down.\n");
-
- CGDisplayRemoveReconfigurationCallback(displayReconfigurationCallBack, this);
-
- // Set Manager shutdown marker variable; this prevents
- // any existing DeviceHandle objects from accessing device.
- pCreateDesc->pLock->pManager = 0;
-
- // Push for thread shutdown *WITH NO WAIT*.
- // This will have the following effect:
- // - Exit command will get enqueued, which will be executed later on the thread itself.
- // - Beyond this point, this DeviceManager object may be deleted by our caller.
- // - Other commands, such as CreateDevice, may execute before ExitCommand, but they will
- // fail gracefully due to pLock->pManager == 0. Future commands can't be enqued
- // after pManager is null.
- // - Once ExitCommand executes, ThreadCommand::Run loop will exit and release the last
- // reference to the thread object.
- pThread->Shutdown();
- pThread.Clear();
-
- DeviceManagerImpl::Shutdown();
-}
-
-ThreadCommandQueue* DeviceManager::GetThreadQueue()
-{
- return pThread;
-}
-
-ThreadId DeviceManager::GetThreadId() const
-{
- return pThread->GetThreadId();
-}
-
-bool DeviceManager::GetDeviceInfo(DeviceInfo* info) const
-{
- if ((info->InfoClassType != Device_Manager) &&
- (info->InfoClassType != Device_None))
- return false;
-
- info->Type = Device_Manager;
- info->Version = 0;
- OVR_strcpy(info->ProductName, DeviceInfo::MaxNameLength, "DeviceManager");
- OVR_strcpy(info->Manufacturer,DeviceInfo::MaxNameLength, "Oculus VR, Inc.");
- return true;
-}
-
-DeviceEnumerator<> DeviceManager::EnumerateDevicesEx(const DeviceEnumerationArgs& args)
-{
- // TBD: Can this be avoided in the future, once proper device notification is in place?
- pThread->PushCall((DeviceManagerImpl*)this,
- &DeviceManager::EnumerateAllFactoryDevices, true);
-
- return DeviceManagerImpl::EnumerateDevicesEx(args);
-}
-
-void DeviceManager::displayReconfigurationCallBack (CGDirectDisplayID display,
- CGDisplayChangeSummaryFlags flags,
- void *userInfo)
-{
- DeviceManager* manager = reinterpret_cast<DeviceManager*>(userInfo);
- OVR_UNUSED(manager);
-
- if (flags & kCGDisplayAddFlag)
- {
- LogText("Display Added, id = %d\n", int(display));
- manager->EnumerateDevices<HMDDevice>();
- }
- else if (flags & kCGDisplayRemoveFlag)
- {
- LogText("Display Removed, id = %d\n", int(display));
- manager->EnumerateDevices<HMDDevice>();
- }
-}
-
-//-------------------------------------------------------------------------------------
-// ***** DeviceManager Thread
-
-DeviceManagerThread::DeviceManagerThread()
- : Thread(ThreadStackSize)
-{
-}
-
-DeviceManagerThread::~DeviceManagerThread()
-{
-}
-
-int DeviceManagerThread::Run()
-{
-
- SetThreadName("OVR::DeviceManagerThread");
- LogText("OVR::DeviceManagerThread - running (ThreadId=0x%p).\n", GetThreadId());
-
- // Store out the run loop ref.
- RunLoop = CFRunLoopGetCurrent();
-
- // Create a 'source' to enable us to signal the run loop to process the command queue.
- CFRunLoopSourceContext sourceContext;
- memset(&sourceContext, 0, sizeof(sourceContext));
- sourceContext.version = 0;
- sourceContext.info = this;
- sourceContext.perform = &staticCommandQueueSourceCallback;
-
- CommandQueueSource = CFRunLoopSourceCreate(kCFAllocatorDefault, 0 , &sourceContext);
-
- CFRunLoopAddSource(RunLoop, CommandQueueSource, kCFRunLoopDefaultMode);
-
-
- // Signal to the parent thread that initialization has finished.
- StartupEvent.SetEvent();
-
-
- ThreadCommand::PopBuffer command;
-
- while(!IsExiting())
- {
- // PopCommand will reset event on empty queue.
- if (PopCommand(&command))
- {
- command.Execute();
- }
- else
- {
- SInt32 exitReason = 0;
- do {
-
- UInt32 waitMs = INT_MAX;
-
- // If devices have time-dependent logic registered, get the longest wait
- // allowed based on current ticks.
- if (!TicksNotifiers.IsEmpty())
- {
- UInt64 ticksMks = Timer::GetTicks();
- UInt32 waitAllowed;
-
- for (UPInt j = 0; j < TicksNotifiers.GetSize(); j++)
- {
- waitAllowed = (UInt32)(TicksNotifiers[j]->OnTicks(ticksMks) / Timer::MksPerMs);
- if (waitAllowed < waitMs)
- waitMs = waitAllowed;
- }
- }
-
- // Enter blocking run loop. We may continue until we timeout in which
- // case it's time to service the ticks. Or if commands arrive in the command
- // queue then the source callback will call 'CFRunLoopStop' causing this
- // to return.
- CFTimeInterval blockInterval = 0.001 * (double) waitMs;
- exitReason = CFRunLoopRunInMode(kCFRunLoopDefaultMode, blockInterval, false);
-
- if (exitReason == kCFRunLoopRunFinished)
- {
- // Maybe this will occur during shutdown?
- break;
- }
- else if (exitReason == kCFRunLoopRunStopped )
- {
- // Commands need processing or we're being shutdown.
- break;
- }
- else if (exitReason == kCFRunLoopRunTimedOut)
- {
- // Timed out so that we can service our ticks callbacks.
- continue;
- }
- else if (exitReason == kCFRunLoopRunHandledSource)
- {
- // Should never occur since the last param when we call
- // 'CFRunLoopRunInMode' is false.
- OVR_ASSERT(false);
- break;
- }
- else
- {
- OVR_ASSERT_LOG(false, ("CFRunLoopRunInMode returned unexpected code"));
- break;
- }
- }
- while(true);
- }
- }
-
-
- CFRunLoopRemoveSource(RunLoop, CommandQueueSource, kCFRunLoopDefaultMode);
- CFRelease(CommandQueueSource);
-
- LogText("OVR::DeviceManagerThread - exiting (ThreadId=0x%p).\n", GetThreadId());
-
- return 0;
-}
-
-void DeviceManagerThread::staticCommandQueueSourceCallback(void* pContext)
-{
- DeviceManagerThread* pThread = (DeviceManagerThread*) pContext;
- pThread->commandQueueSourceCallback();
-}
-
-void DeviceManagerThread::commandQueueSourceCallback()
-{
- CFRunLoopStop(RunLoop);
-}
-
-bool DeviceManagerThread::AddTicksNotifier(Notifier* notify)
-{
- TicksNotifiers.PushBack(notify);
- return true;
-}
-
-bool DeviceManagerThread::RemoveTicksNotifier(Notifier* notify)
-{
- for (UPInt i = 0; i < TicksNotifiers.GetSize(); i++)
- {
- if (TicksNotifiers[i] == notify)
- {
- TicksNotifiers.RemoveAt(i);
- return true;
- }
- }
- return false;
-}
-
-void DeviceManagerThread::Shutdown()
-{
- // Push for thread shutdown *WITH NO WAIT*.
- // This will have the following effect:
- // - Exit command will get enqueued, which will be executed later on the thread itself.
- // - Beyond this point, this DeviceManager object may be deleted by our caller.
- // - Other commands, such as CreateDevice, may execute before ExitCommand, but they will
- // fail gracefully due to pLock->pManager == 0. Future commands can't be enqued
- // after pManager is null.
- // - Once ExitCommand executes, ThreadCommand::Run loop will exit and release the last
- // reference to the thread object.
- PushExitCommand(false);
-
- // make sure CFRunLoopRunInMode is woken up
- CFRunLoopSourceSignal(CommandQueueSource);
- CFRunLoopWakeUp(RunLoop);
-}
-
-} // namespace OSX
-
-
-//-------------------------------------------------------------------------------------
-// ***** Creation
-
-// Creates a new DeviceManager and initializes OVR.
-DeviceManager* DeviceManager::Create()
-{
-
- if (!System::IsInitialized())
- {
- // Use custom message, since Log is not yet installed.
- OVR_DEBUG_STATEMENT(Log::GetDefaultLog()->
- LogMessage(Log_Debug, "DeviceManager::Create failed - OVR::System not initialized"); );
- return 0;
- }
-
- Ptr<OSX::DeviceManager> manager = *new OSX::DeviceManager;
-
- if (manager)
- {
- if (manager->Initialize(0))
- {
- manager->AddFactory(&LatencyTestDeviceFactory::Instance);
- manager->AddFactory(&SensorDeviceFactory::Instance);
- manager->AddFactory(&OSX::HMDDeviceFactory::Instance);
-
- manager->AddRef();
- }
- else
- {
- manager.Clear();
- }
- }
-
- return manager.GetPtr();
-}
-
-} // namespace OVR
+/************************************************************************************
+
+Filename : OVR_OSX_DeviceManager.cpp
+Content : OSX specific DeviceManager implementation.
+Created : March 14, 2013
+Authors : Lee Cooper
+
+Copyright : Copyright 2013 Oculus VR, Inc. All Rights reserved.
+
+Use of this software is subject to the terms of the Oculus license
+agreement provided at the time of installation or download, or which
+otherwise accompanies this software in either electronic or hard copy form.
+
+*************************************************************************************/
+
+#include "OVR_OSX_DeviceManager.h"
+
+// Sensor & HMD Factories
+#include "OVR_LatencyTestImpl.h"
+#include "OVR_SensorImpl.h"
+#include "OVR_OSX_HMDDevice.h"
+#include "OVR_OSX_HIDDevice.h"
+
+#include "Kernel/OVR_Timer.h"
+#include "Kernel/OVR_Std.h"
+#include "Kernel/OVR_Log.h"
+
+#include <IOKit/hid/IOHIDManager.h>
+#include <IOKit/hid/IOHIDKeys.h>
+
+
+namespace OVR { namespace OSX {
+
+//-------------------------------------------------------------------------------------
+// **** OSX::DeviceManager
+
+DeviceManager::DeviceManager()
+{
+}
+
+DeviceManager::~DeviceManager()
+{
+ OVR_DEBUG_LOG(("OSX::DeviceManager::~DeviceManager was called"));
+}
+
+bool DeviceManager::Initialize(DeviceBase*)
+{
+ if (!DeviceManagerImpl::Initialize(0))
+ return false;
+
+ // Start the background thread.
+ pThread = *new DeviceManagerThread();
+ if (!pThread || !pThread->Start())
+ return false;
+
+ // Wait for the thread to be fully up and running.
+ pThread->StartupEvent.Wait();
+
+ // Do this now that we know the thread's run loop.
+ HidDeviceManager = *HIDDeviceManager::CreateInternal(this);
+
+ CGDisplayRegisterReconfigurationCallback(displayReconfigurationCallBack, this);
+
+ pCreateDesc->pDevice = this;
+ LogText("OVR::DeviceManager - initialized.\n");
+
+ return true;
+}
+
+void DeviceManager::Shutdown()
+{
+ LogText("OVR::DeviceManager - shutting down.\n");
+
+ CGDisplayRemoveReconfigurationCallback(displayReconfigurationCallBack, this);
+
+ // Set Manager shutdown marker variable; this prevents
+ // any existing DeviceHandle objects from accessing device.
+ pCreateDesc->pLock->pManager = 0;
+
+ // Push for thread shutdown *WITH NO WAIT*.
+ // This will have the following effect:
+ // - Exit command will get enqueued, which will be executed later on the thread itself.
+ // - Beyond this point, this DeviceManager object may be deleted by our caller.
+ // - Other commands, such as CreateDevice, may execute before ExitCommand, but they will
+ // fail gracefully due to pLock->pManager == 0. Future commands can't be enqued
+ // after pManager is null.
+ // - Once ExitCommand executes, ThreadCommand::Run loop will exit and release the last
+ // reference to the thread object.
+ pThread->Shutdown();
+ pThread.Clear();
+
+ DeviceManagerImpl::Shutdown();
+}
+
+ThreadCommandQueue* DeviceManager::GetThreadQueue()
+{
+ return pThread;
+}
+
+ThreadId DeviceManager::GetThreadId() const
+{
+ return pThread->GetThreadId();
+}
+
+bool DeviceManager::GetDeviceInfo(DeviceInfo* info) const
+{
+ if ((info->InfoClassType != Device_Manager) &&
+ (info->InfoClassType != Device_None))
+ return false;
+
+ info->Type = Device_Manager;
+ info->Version = 0;
+ OVR_strcpy(info->ProductName, DeviceInfo::MaxNameLength, "DeviceManager");
+ OVR_strcpy(info->Manufacturer,DeviceInfo::MaxNameLength, "Oculus VR, Inc.");
+ return true;
+}
+
+DeviceEnumerator<> DeviceManager::EnumerateDevicesEx(const DeviceEnumerationArgs& args)
+{
+ // TBD: Can this be avoided in the future, once proper device notification is in place?
+ pThread->PushCall((DeviceManagerImpl*)this,
+ &DeviceManager::EnumerateAllFactoryDevices, true);
+
+ return DeviceManagerImpl::EnumerateDevicesEx(args);
+}
+
+void DeviceManager::displayReconfigurationCallBack (CGDirectDisplayID display,
+ CGDisplayChangeSummaryFlags flags,
+ void *userInfo)
+{
+ DeviceManager* manager = reinterpret_cast<DeviceManager*>(userInfo);
+ OVR_UNUSED(manager);
+
+ if (flags & kCGDisplayAddFlag)
+ {
+ LogText("Display Added, id = %d\n", int(display));
+ manager->EnumerateDevices<HMDDevice>();
+ }
+ else if (flags & kCGDisplayRemoveFlag)
+ {
+ LogText("Display Removed, id = %d\n", int(display));
+ manager->EnumerateDevices<HMDDevice>();
+ }
+}
+
+//-------------------------------------------------------------------------------------
+// ***** DeviceManager Thread
+
+DeviceManagerThread::DeviceManagerThread()
+ : Thread(ThreadStackSize)
+{
+}
+
+DeviceManagerThread::~DeviceManagerThread()
+{
+}
+
+int DeviceManagerThread::Run()
+{
+
+ SetThreadName("OVR::DeviceManagerThread");
+ LogText("OVR::DeviceManagerThread - running (ThreadId=0x%p).\n", GetThreadId());
+
+ // Store out the run loop ref.
+ RunLoop = CFRunLoopGetCurrent();
+
+ // Create a 'source' to enable us to signal the run loop to process the command queue.
+ CFRunLoopSourceContext sourceContext;
+ memset(&sourceContext, 0, sizeof(sourceContext));
+ sourceContext.version = 0;
+ sourceContext.info = this;
+ sourceContext.perform = &staticCommandQueueSourceCallback;
+
+ CommandQueueSource = CFRunLoopSourceCreate(kCFAllocatorDefault, 0 , &sourceContext);
+
+ CFRunLoopAddSource(RunLoop, CommandQueueSource, kCFRunLoopDefaultMode);
+
+
+ // Signal to the parent thread that initialization has finished.
+ StartupEvent.SetEvent();
+
+
+ ThreadCommand::PopBuffer command;
+
+ while(!IsExiting())
+ {
+ // PopCommand will reset event on empty queue.
+ if (PopCommand(&command))
+ {
+ command.Execute();
+ }
+ else
+ {
+ SInt32 exitReason = 0;
+ do {
+
+ UInt32 waitMs = INT_MAX;
+
+ // If devices have time-dependent logic registered, get the longest wait
+ // allowed based on current ticks.
+ if (!TicksNotifiers.IsEmpty())
+ {
+ UInt64 ticksMks = Timer::GetTicks();
+ UInt32 waitAllowed;
+
+ for (UPInt j = 0; j < TicksNotifiers.GetSize(); j++)
+ {
+ waitAllowed = (UInt32)(TicksNotifiers[j]->OnTicks(ticksMks) / Timer::MksPerMs);
+ if (waitAllowed < waitMs)
+ waitMs = waitAllowed;
+ }
+ }
+
+ // Enter blocking run loop. We may continue until we timeout in which
+ // case it's time to service the ticks. Or if commands arrive in the command
+ // queue then the source callback will call 'CFRunLoopStop' causing this
+ // to return.
+ CFTimeInterval blockInterval = 0.001 * (double) waitMs;
+ exitReason = CFRunLoopRunInMode(kCFRunLoopDefaultMode, blockInterval, false);
+
+ if (exitReason == kCFRunLoopRunFinished)
+ {
+ // Maybe this will occur during shutdown?
+ break;
+ }
+ else if (exitReason == kCFRunLoopRunStopped )
+ {
+ // Commands need processing or we're being shutdown.
+ break;
+ }
+ else if (exitReason == kCFRunLoopRunTimedOut)
+ {
+ // Timed out so that we can service our ticks callbacks.
+ continue;
+ }
+ else if (exitReason == kCFRunLoopRunHandledSource)
+ {
+ // Should never occur since the last param when we call
+ // 'CFRunLoopRunInMode' is false.
+ OVR_ASSERT(false);
+ break;
+ }
+ else
+ {
+ OVR_ASSERT_LOG(false, ("CFRunLoopRunInMode returned unexpected code"));
+ break;
+ }
+ }
+ while(true);
+ }
+ }
+
+
+ CFRunLoopRemoveSource(RunLoop, CommandQueueSource, kCFRunLoopDefaultMode);
+ CFRelease(CommandQueueSource);
+
+ LogText("OVR::DeviceManagerThread - exiting (ThreadId=0x%p).\n", GetThreadId());
+
+ return 0;
+}
+
+void DeviceManagerThread::staticCommandQueueSourceCallback(void* pContext)
+{
+ DeviceManagerThread* pThread = (DeviceManagerThread*) pContext;
+ pThread->commandQueueSourceCallback();
+}
+
+void DeviceManagerThread::commandQueueSourceCallback()
+{
+ CFRunLoopStop(RunLoop);
+}
+
+bool DeviceManagerThread::AddTicksNotifier(Notifier* notify)
+{
+ TicksNotifiers.PushBack(notify);
+ return true;
+}
+
+bool DeviceManagerThread::RemoveTicksNotifier(Notifier* notify)
+{
+ for (UPInt i = 0; i < TicksNotifiers.GetSize(); i++)
+ {
+ if (TicksNotifiers[i] == notify)
+ {
+ TicksNotifiers.RemoveAt(i);
+ return true;
+ }
+ }
+ return false;
+}
+
+void DeviceManagerThread::Shutdown()
+{
+ // Push for thread shutdown *WITH NO WAIT*.
+ // This will have the following effect:
+ // - Exit command will get enqueued, which will be executed later on the thread itself.
+ // - Beyond this point, this DeviceManager object may be deleted by our caller.
+ // - Other commands, such as CreateDevice, may execute before ExitCommand, but they will
+ // fail gracefully due to pLock->pManager == 0. Future commands can't be enqued
+ // after pManager is null.
+ // - Once ExitCommand executes, ThreadCommand::Run loop will exit and release the last
+ // reference to the thread object.
+ PushExitCommand(false);
+
+ // make sure CFRunLoopRunInMode is woken up
+ CFRunLoopSourceSignal(CommandQueueSource);
+ CFRunLoopWakeUp(RunLoop);
+}
+
+} // namespace OSX
+
+
+//-------------------------------------------------------------------------------------
+// ***** Creation
+
+// Creates a new DeviceManager and initializes OVR.
+DeviceManager* DeviceManager::Create()
+{
+
+ if (!System::IsInitialized())
+ {
+ // Use custom message, since Log is not yet installed.
+ OVR_DEBUG_STATEMENT(Log::GetDefaultLog()->
+ LogMessage(Log_Debug, "DeviceManager::Create failed - OVR::System not initialized"); );
+ return 0;
+ }
+
+ Ptr<OSX::DeviceManager> manager = *new OSX::DeviceManager;
+
+ if (manager)
+ {
+ if (manager->Initialize(0))
+ {
+ manager->AddFactory(&LatencyTestDeviceFactory::Instance);
+ manager->AddFactory(&SensorDeviceFactory::Instance);
+ manager->AddFactory(&OSX::HMDDeviceFactory::Instance);
+
+ manager->AddRef();
+ }
+ else
+ {
+ manager.Clear();
+ }
+ }
+
+ return manager.GetPtr();
+}
+
+} // namespace OVR
diff --git a/LibOVR/Src/OVR_OSX_DeviceManager.h b/LibOVR/Src/OVR_OSX_DeviceManager.h
index 02ba661..f272a35 100644
--- a/LibOVR/Src/OVR_OSX_DeviceManager.h
+++ b/LibOVR/Src/OVR_OSX_DeviceManager.h
@@ -1,119 +1,119 @@
-/************************************************************************************
-
-Filename : OVR_OSX_DeviceManager.h
-Content : OSX specific DeviceManager header.
-Created : March 14, 2013
-Authors : Lee Cooper
-
-Copyright : Copyright 2013 Oculus VR, Inc. All Rights reserved.
-
-Use of this software is subject to the terms of the Oculus license
-agreement provided at the time of installation or download, or which
-otherwise accompanies this software in either electronic or hard copy form.
-
-*************************************************************************************/
-
-#ifndef OVR_OSX_DeviceManager_h
-#define OVR_OSX_DeviceManager_h
-
-#include "OVR_DeviceImpl.h"
-
-#include "Kernel/OVR_Timer.h"
-
-#include <IOKit/hid/IOHIDManager.h>
-#include <CoreGraphics/CGDirectDisplay.h>
-#include <CoreGraphics/CGDisplayConfiguration.h>
-
-
-namespace OVR { namespace OSX {
-
-class DeviceManagerThread;
-
-//-------------------------------------------------------------------------------------
-// ***** OSX DeviceManager
-
-class DeviceManager : public DeviceManagerImpl
-{
-public:
- DeviceManager();
- ~DeviceManager();
-
- // Initialize/Shutdown manager thread.
- virtual bool Initialize(DeviceBase* parent);
- virtual void Shutdown();
-
- virtual ThreadCommandQueue* GetThreadQueue();
- virtual ThreadId GetThreadId() const;
-
- virtual DeviceEnumerator<> EnumerateDevicesEx(const DeviceEnumerationArgs& args);
-
- virtual bool GetDeviceInfo(DeviceInfo* info) const;
-
-protected:
- static void displayReconfigurationCallBack (CGDirectDisplayID display,
- CGDisplayChangeSummaryFlags flags,
- void *userInfo);
-
-public: // data
- Ptr<DeviceManagerThread> pThread;
-};
-
-//-------------------------------------------------------------------------------------
-// ***** Device Manager Background Thread
-
-class DeviceManagerThread : public Thread, public ThreadCommandQueue
-{
- friend class DeviceManager;
- enum { ThreadStackSize = 32 * 1024 };
-public:
- DeviceManagerThread();
- ~DeviceManagerThread();
-
- virtual int Run();
-
- // ThreadCommandQueue notifications for CommandEvent handling.
- virtual void OnPushNonEmpty_Locked()
- {
- CFRunLoopSourceSignal(CommandQueueSource);
- CFRunLoopWakeUp(RunLoop);
- }
-
- virtual void OnPopEmpty_Locked() {}
-
-
- // Notifier used for different updates (EVENT or regular timing or messages).
- class Notifier
- {
- public:
-
- // Called when timing ticks are updated. // Returns the largest number of microseconds
- // this function can wait till next call.
- virtual UInt64 OnTicks(UInt64 ticksMks)
- { OVR_UNUSED1(ticksMks); return Timer::MksPerSecond * 1000; }
- };
-
- // Add notifier that will be called at regular intervals.
- bool AddTicksNotifier(Notifier* notify);
- bool RemoveTicksNotifier(Notifier* notify);
-
- CFRunLoopRef GetRunLoop()
- { return RunLoop; }
-
- void Shutdown();
-private:
- CFRunLoopRef RunLoop;
-
- CFRunLoopSourceRef CommandQueueSource;
-
- static void staticCommandQueueSourceCallback(void* pContext);
- void commandQueueSourceCallback();
-
- Event StartupEvent;
-
- // Ticks notifiers. Used for time-dependent events such as keep-alive.
- Array<Notifier*> TicksNotifiers;
-};
-
-}} // namespace OSX::OVR
-
-#endif // OVR_OSX_DeviceManager_h
+/************************************************************************************
+
+Filename : OVR_OSX_DeviceManager.h
+Content : OSX specific DeviceManager header.
+Created : March 14, 2013
+Authors : Lee Cooper
+
+Copyright : Copyright 2013 Oculus VR, Inc. All Rights reserved.
+
+Use of this software is subject to the terms of the Oculus license
+agreement provided at the time of installation or download, or which
+otherwise accompanies this software in either electronic or hard copy form.
+
+*************************************************************************************/
+
+#ifndef OVR_OSX_DeviceManager_h
+#define OVR_OSX_DeviceManager_h
+
+#include "OVR_DeviceImpl.h"
+
+#include "Kernel/OVR_Timer.h"
+
+#include <IOKit/hid/IOHIDManager.h>
+#include <CoreGraphics/CGDirectDisplay.h>
+#include <CoreGraphics/CGDisplayConfiguration.h>
+
+
+namespace OVR { namespace OSX {
+
+class DeviceManagerThread;
+
+//-------------------------------------------------------------------------------------
+// ***** OSX DeviceManager
+
+class DeviceManager : public DeviceManagerImpl
+{
+public:
+ DeviceManager();
+ ~DeviceManager();
+
+ // Initialize/Shutdown manager thread.
+ virtual bool Initialize(DeviceBase* parent);
+ virtual void Shutdown();
+
+ virtual ThreadCommandQueue* GetThreadQueue();
+ virtual ThreadId GetThreadId() const;
+
+ virtual DeviceEnumerator<> EnumerateDevicesEx(const DeviceEnumerationArgs& args);
+
+ virtual bool GetDeviceInfo(DeviceInfo* info) const;
+
+protected:
+ static void displayReconfigurationCallBack (CGDirectDisplayID display,
+ CGDisplayChangeSummaryFlags flags,
+ void *userInfo);
+
+public: // data
+ Ptr<DeviceManagerThread> pThread;
+};
+
+//-------------------------------------------------------------------------------------
+// ***** Device Manager Background Thread
+
+class DeviceManagerThread : public Thread, public ThreadCommandQueue
+{
+ friend class DeviceManager;
+ enum { ThreadStackSize = 32 * 1024 };
+public:
+ DeviceManagerThread();
+ ~DeviceManagerThread();
+
+ virtual int Run();
+
+ // ThreadCommandQueue notifications for CommandEvent handling.
+ virtual void OnPushNonEmpty_Locked()
+ {
+ CFRunLoopSourceSignal(CommandQueueSource);
+ CFRunLoopWakeUp(RunLoop);
+ }
+
+ virtual void OnPopEmpty_Locked() {}
+
+
+ // Notifier used for different updates (EVENT or regular timing or messages).
+ class Notifier
+ {
+ public:
+
+ // Called when timing ticks are updated. // Returns the largest number of microseconds
+ // this function can wait till next call.
+ virtual UInt64 OnTicks(UInt64 ticksMks)
+ { OVR_UNUSED1(ticksMks); return Timer::MksPerSecond * 1000; }
+ };
+
+ // Add notifier that will be called at regular intervals.
+ bool AddTicksNotifier(Notifier* notify);
+ bool RemoveTicksNotifier(Notifier* notify);
+
+ CFRunLoopRef GetRunLoop()
+ { return RunLoop; }
+
+ void Shutdown();
+private:
+ CFRunLoopRef RunLoop;
+
+ CFRunLoopSourceRef CommandQueueSource;
+
+ static void staticCommandQueueSourceCallback(void* pContext);
+ void commandQueueSourceCallback();
+
+ Event StartupEvent;
+
+ // Ticks notifiers. Used for time-dependent events such as keep-alive.
+ Array<Notifier*> TicksNotifiers;
+};
+
+}} // namespace OSX::OVR
+
+#endif // OVR_OSX_DeviceManager_h
diff --git a/LibOVR/Src/OVR_OSX_HIDDevice.cpp b/LibOVR/Src/OVR_OSX_HIDDevice.cpp
index 40b63c9..e954ef4 100644
--- a/LibOVR/Src/OVR_OSX_HIDDevice.cpp
+++ b/LibOVR/Src/OVR_OSX_HIDDevice.cpp
@@ -1,899 +1,899 @@
-/************************************************************************************
-Filename : OVR_OSX_HIDDevice.cpp
-Content : OSX HID device implementation.
-Created : February 26, 2013
-Authors : Lee Cooper
-
-Copyright : Copyright 2013 Oculus VR, Inc. All Rights reserved.
-
-Use of this software is subject to the terms of the Oculus license
-agreement provided at the time of installation or download, or which
-otherwise accompanies this software in either electronic or hard copy form.
-
-*************************************************************************************/
-
-#include "OVR_OSX_HIDDevice.h"
-
-#include <IOKit/usb/IOUSBLib.h>
-
-namespace OVR { namespace OSX {
-
-static const UInt32 MAX_QUEUED_INPUT_REPORTS = 5;
-
-//-------------------------------------------------------------------------------------
-// **** OSX::DeviceManager
-
-HIDDeviceManager::HIDDeviceManager(DeviceManager* manager)
- : DevManager(manager)
-{
- HIDManager = NULL;
-}
-
-HIDDeviceManager::~HIDDeviceManager()
-{
-}
-
-CFRunLoopRef HIDDeviceManager::getRunLoop()
-{
- if (DevManager != NULL)
- {
- return DevManager->pThread->GetRunLoop();
- }
-
- return CFRunLoopGetCurrent();
-}
-
-bool HIDDeviceManager::initializeManager()
-{
- if (HIDManager != NULL)
- {
- return true;
- }
-
- HIDManager = IOHIDManagerCreate(kCFAllocatorDefault, kIOHIDOptionsTypeNone);
-
- if (!HIDManager)
- {
- return false;
- }
-
- // Create a Matching Dictionary
- CFMutableDictionaryRef matchDict =
- CFDictionaryCreateMutable(kCFAllocatorDefault,
- 2,
- &kCFTypeDictionaryKeyCallBacks,
- &kCFTypeDictionaryValueCallBacks);
-
- // Specify a device manufacturer in the Matching Dictionary
- UInt32 vendorId = Oculus_VendorId;
- CFNumberRef vendorIdRef = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &vendorId);
- CFDictionarySetValue(matchDict,
- CFSTR(kIOHIDVendorIDKey),
- vendorIdRef);
- // Register the Matching Dictionary to the HID Manager
- IOHIDManagerSetDeviceMatching(HIDManager, matchDict);
- CFRelease(vendorIdRef);
- CFRelease(matchDict);
-
- // Register a callback for USB device detection with the HID Manager
- IOHIDManagerRegisterDeviceMatchingCallback(HIDManager, &staticDeviceMatchingCallback, this);
-
- IOHIDManagerScheduleWithRunLoop(HIDManager, getRunLoop(), kCFRunLoopDefaultMode);
-
- return true;
-}
-
-bool HIDDeviceManager::Initialize()
-{
- return initializeManager();
-}
-
-void HIDDeviceManager::Shutdown()
-{
- OVR_ASSERT_LOG(HIDManager, ("Should have called 'Initialize' before 'Shutdown'."));
- CFRelease(HIDManager);
-
- LogText("OVR::OSX::HIDDeviceManager - shutting down.\n");
-}
-
-bool HIDDeviceManager::getIntProperty(IOHIDDeviceRef device, CFStringRef propertyName, SInt32* pResult)
-{
-
- CFTypeRef ref = IOHIDDeviceGetProperty(device, propertyName);
-
- if (!ref)
- {
- return false;
- }
-
- if (CFGetTypeID(ref) != CFNumberGetTypeID())
- {
- return false;
- }
-
- CFNumberGetValue((CFNumberRef) ref, kCFNumberSInt32Type, pResult);
-
- return true;
-}
-
-bool HIDDeviceManager::initVendorProductVersion(IOHIDDeviceRef device, HIDDeviceDesc* pDevDesc)
-{
-
- if (!getVendorId(device, &(pDevDesc->VendorId)))
- {
- return false;
- }
-
- if (!getProductId(device, &(pDevDesc->ProductId)))
- {
- return false;
- }
-
- return true;
-}
-
-bool HIDDeviceManager::initUsage(IOHIDDeviceRef device, HIDDeviceDesc* pDevDesc)
-{
-
- SInt32 result;
-
- if (!getIntProperty(device, CFSTR(kIOHIDPrimaryUsagePageKey), &result))
- {
- return false;
- }
-
- pDevDesc->UsagePage = result;
-
-
- if (!getIntProperty(device, CFSTR(kIOHIDPrimaryUsageKey), &result))
- {
- return false;
- }
-
- pDevDesc->Usage = result;
-
- return true;
-}
-
-bool HIDDeviceManager::initSerialNumber(IOHIDDeviceRef device, HIDDeviceDesc* pDevDesc)
-{
- return getSerialNumberString(device, &(pDevDesc->SerialNumber));
-}
-
-bool HIDDeviceManager::initStrings(IOHIDDeviceRef device, HIDDeviceDesc* pDevDesc)
-{
-
- // Regardless of whether they fail we'll try and get the remaining.
- getStringProperty(device, CFSTR(kIOHIDManufacturerKey), &(pDevDesc->Manufacturer));
- getStringProperty(device, CFSTR(kIOHIDProductKey), &(pDevDesc->Product));
-
- return true;
-}
-
-bool HIDDeviceManager::getStringProperty(IOHIDDeviceRef device,
- CFStringRef propertyName,
- String* pResult)
-{
-
- CFStringRef str = (CFStringRef) IOHIDDeviceGetProperty(device, propertyName);
-
- if (!str)
- {
- return false;
- }
-
- CFIndex length = CFStringGetLength(str);
- CFRange range = CFRangeMake(0, length);
-
- // Test the conversion first to get required buffer size.
- CFIndex bufferLength;
- CFIndex numberOfChars = CFStringGetBytes(str,
- range,
- kCFStringEncodingUTF8,
- (char) '?',
- FALSE,
- NULL,
- 0,
- &bufferLength);
-
- if (numberOfChars == 0)
- {
- return false;
- }
-
- // Now allocate buffer.
- char* buffer = new char[bufferLength+1];
-
- numberOfChars = CFStringGetBytes(str,
- range,
- kCFStringEncodingUTF8,
- (char) '?',
- FALSE,
- (UInt8*) buffer,
- bufferLength,
- NULL);
- OVR_ASSERT_LOG(numberOfChars != 0, ("CFStringGetBytes failed."));
-
- buffer[bufferLength] = '\0';
- *pResult = String(buffer);
-
- return true;
-}
-
-bool HIDDeviceManager::getVendorId(IOHIDDeviceRef device, UInt16* pResult)
-{
- SInt32 result;
-
- if (!getIntProperty(device, CFSTR(kIOHIDVendorIDKey), &result))
- {
- return false;
- }
-
- *pResult = result;
-
- return true;
-}
-
-bool HIDDeviceManager::getProductId(IOHIDDeviceRef device, UInt16* pResult)
-{
- SInt32 result;
-
- if (!getIntProperty(device, CFSTR(kIOHIDProductIDKey), &result))
- {
- return false;
- }
-
- *pResult = result;
-
- return true;
-}
-
-bool HIDDeviceManager::getLocationId(IOHIDDeviceRef device, SInt32* pResult)
-{
- SInt32 result;
-
- if (!getIntProperty(device, CFSTR(kIOHIDLocationIDKey), &result))
- {
- return false;
- }
-
- *pResult = result;
-
- return true;
-}
-
-bool HIDDeviceManager::getSerialNumberString(IOHIDDeviceRef device, String* pResult)
-{
-
- if (!getStringProperty(device, CFSTR(kIOHIDSerialNumberKey), pResult))
- {
- return false;
- }
-
- return true;
-}
-
-bool HIDDeviceManager::getPath(IOHIDDeviceRef device, String* pPath)
-{
-
- String transport;
- if (!getStringProperty(device, CFSTR(kIOHIDTransportKey), &transport))
- {
- return false;
- }
-
- UInt16 vendorId;
- if (!getVendorId(device, &vendorId))
- {
- return false;
- }
-
- UInt16 productId;
- if (!getProductId(device, &productId))
- {
- return false;
- }
-
- String serialNumber;
- if (!getSerialNumberString(device, &serialNumber))
- {
- return false;
- }
-
-
- StringBuffer buffer;
- buffer.AppendFormat("%s:vid=%04hx:pid=%04hx:ser=%s",
- transport.ToCStr(),
- vendorId,
- productId,
- serialNumber.ToCStr());
-
- *pPath = String(buffer);
-
- return true;
-}
-
-bool HIDDeviceManager::Enumerate(HIDEnumerateVisitor* enumVisitor)
-{
- if (!initializeManager())
- {
- return false;
- }
-
-
- CFSetRef deviceSet = IOHIDManagerCopyDevices(HIDManager);
- if (!deviceSet)
- return false;
-
- CFIndex deviceCount = CFSetGetCount(deviceSet);
-
- // Allocate a block of memory and read the set into it.
- IOHIDDeviceRef* devices = (IOHIDDeviceRef*) OVR_ALLOC(sizeof(IOHIDDeviceRef) * deviceCount);
- CFSetGetValues(deviceSet, (const void **) devices);
-
-
- // Iterate over devices.
- for (CFIndex deviceIndex = 0; deviceIndex < deviceCount; deviceIndex++)
- {
- IOHIDDeviceRef hidDev = devices[deviceIndex];
-
- if (!hidDev)
- {
- continue;
- }
-
- HIDDeviceDesc devDesc;
-
- if (getPath(hidDev, &(devDesc.Path)) &&
- initVendorProductVersion(hidDev, &devDesc) &&
- enumVisitor->MatchVendorProduct(devDesc.VendorId, devDesc.ProductId) &&
- initUsage(hidDev, &devDesc))
- {
- initStrings(hidDev, &devDesc);
- initSerialNumber(hidDev, &devDesc);
-
- // Look for the device to check if it is already opened.
- Ptr<DeviceCreateDesc> existingDevice = DevManager->FindHIDDevice(devDesc);
- // if device exists and it is opened then most likely the CreateHIDFile
- // will fail; therefore, we just set Enumerated to 'true' and continue.
- if (existingDevice && existingDevice->pDevice)
- {
- existingDevice->Enumerated = true;
- continue;
- }
-
- // Construct minimal device that the visitor callback can get feature reports from.
- OSX::HIDDevice device(this, hidDev);
-
- enumVisitor->Visit(device, devDesc);
- }
- }
-
- OVR_FREE(devices);
- CFRelease(deviceSet);
-
- return true;
-}
-
-OVR::HIDDevice* HIDDeviceManager::Open(const String& path)
-{
-
- Ptr<OSX::HIDDevice> device = *new OSX::HIDDevice(this);
-
- if (!device->HIDInitialize(path))
- {
- return NULL;
- }
-
- device->AddRef();
-
- return device;
-}
-
-bool HIDDeviceManager::getFullDesc(IOHIDDeviceRef device, HIDDeviceDesc* desc)
-{
-
- if (!initVendorProductVersion(device, desc))
- {
- return false;
- }
-
- if (!initUsage(device, desc))
- {
- return false;
- }
-
- if (!initSerialNumber(device, desc))
- {
- return false;
- }
-
- initStrings(device, desc);
-
- return true;
-}
-
-// New USB device specified in the matching dictionary has been added (callback function)
-void HIDDeviceManager::staticDeviceMatchingCallback(void *inContext,
- IOReturn inResult,
- void *inSender,
- IOHIDDeviceRef inIOHIDDeviceRef)
-{
- HIDDeviceManager* hidMgr = static_cast<HIDDeviceManager*>(inContext);
- HIDDeviceDesc hidDevDesc;
- hidMgr->getPath(inIOHIDDeviceRef, &hidDevDesc.Path);
- hidMgr->getFullDesc(inIOHIDDeviceRef, &hidDevDesc);
-
- hidMgr->DevManager->DetectHIDDevice(hidDevDesc);
-}
-
-//-------------------------------------------------------------------------------------
-// **** OSX::HIDDevice
-
-HIDDevice::HIDDevice(HIDDeviceManager* manager)
- : HIDManager(manager), InMinimalMode(false)
-{
- Device = NULL;
- RepluggedNotificationPort = 0;
-}
-
-// This is a minimal constructor used during enumeration for us to pass
-// a HIDDevice to the visit function (so that it can query feature reports).
-HIDDevice::HIDDevice(HIDDeviceManager* manager, IOHIDDeviceRef device)
-: HIDManager(manager), Device(device), InMinimalMode(true)
-{
- RepluggedNotificationPort = 0;
-}
-
-HIDDevice::~HIDDevice()
-{
- if (!InMinimalMode)
- {
- HIDShutdown();
- }
-}
-
-bool HIDDevice::HIDInitialize(const String& path)
-{
-
- DevDesc.Path = path;
-
- if (!openDevice())
- {
- LogText("OVR::OSX::HIDDevice - Failed to open HIDDevice: %s", path.ToCStr());
- return false;
- }
-
- // Setup notification for when a device is unplugged and plugged back in.
- if (!setupDevicePluggedInNotification())
- {
- LogText("OVR::OSX::HIDDevice - Failed to setup notification for when device plugged back in.");
- closeDevice(false);
- return false;
- }
-
- HIDManager->DevManager->pThread->AddTicksNotifier(this);
-
-
- LogText("OVR::OSX::HIDDevice - Opened '%s'\n"
- " Manufacturer:'%s' Product:'%s' Serial#:'%s'\n",
- DevDesc.Path.ToCStr(),
- DevDesc.Manufacturer.ToCStr(), DevDesc.Product.ToCStr(),
- DevDesc.SerialNumber.ToCStr());
-
- return true;
-}
-
-bool HIDDevice::initInfo()
-{
- // Device must have been successfully opened.
- OVR_ASSERT(Device);
-
-
- // Get report lengths.
- SInt32 bufferLength;
- bool getResult = HIDManager->getIntProperty(Device, CFSTR(kIOHIDMaxInputReportSizeKey), &bufferLength);
- OVR_ASSERT(getResult);
- InputReportBufferLength = (UInt16) bufferLength;
-
- getResult = HIDManager->getIntProperty(Device, CFSTR(kIOHIDMaxOutputReportSizeKey), &bufferLength);
- OVR_ASSERT(getResult);
- OutputReportBufferLength = (UInt16) bufferLength;
-
- getResult = HIDManager->getIntProperty(Device, CFSTR(kIOHIDMaxFeatureReportSizeKey), &bufferLength);
- OVR_ASSERT(getResult);
- FeatureReportBufferLength = (UInt16) bufferLength;
-
-
- if (ReadBufferSize < InputReportBufferLength)
- {
- OVR_ASSERT_LOG(false, ("Input report buffer length is bigger than read buffer."));
- return false;
- }
-
- // Get device desc.
- if (!HIDManager->getFullDesc(Device, &DevDesc))
- {
- OVR_ASSERT_LOG(false, ("Failed to get device desc while initializing device."));
- return false;
- }
-
- return true;
-}
-
-void HIDDevice::staticDeviceAddedCallback(void* pContext, io_iterator_t iterator)
-{
- HIDDevice* pDevice = (HIDDevice*) pContext;
- pDevice->deviceAddedCallback(iterator);
-}
-
-void HIDDevice::deviceAddedCallback(io_iterator_t iterator)
-{
-
- if (Device == NULL)
- {
- if (openDevice())
- {
- LogText("OVR::OSX::HIDDevice - Reopened device : %s", DevDesc.Path.ToCStr());
-
- Ptr<DeviceCreateDesc> existingHIDDev = HIDManager->DevManager->FindHIDDevice(DevDesc);
- if (existingHIDDev && existingHIDDev->pDevice)
- {
- HIDManager->DevManager->CallOnDeviceAdded(existingHIDDev);
- }
- }
- }
-
- // Reset callback.
- while (IOIteratorNext(iterator))
- ;
-}
-
-bool HIDDevice::openDevice()
-{
-
- // Have to iterate through devices again to generate paths.
- CFSetRef deviceSet = IOHIDManagerCopyDevices(HIDManager->HIDManager);
- CFIndex deviceCount = CFSetGetCount(deviceSet);
-
- // Allocate a block of memory and read the set into it.
- IOHIDDeviceRef* devices = (IOHIDDeviceRef*) OVR_ALLOC(sizeof(IOHIDDeviceRef) * deviceCount);
- CFSetGetValues(deviceSet, (const void **) devices);
-
-
- // Iterate over devices.
- IOHIDDeviceRef device = NULL;
-
- for (CFIndex deviceIndex = 0; deviceIndex < deviceCount; deviceIndex++)
- {
- IOHIDDeviceRef tmpDevice = devices[deviceIndex];
-
- if (!tmpDevice)
- {
- continue;
- }
-
- String path;
- if (!HIDManager->getPath(tmpDevice, &path))
- {
- continue;
- }
-
- if (path == DevDesc.Path)
- {
- device = tmpDevice;
- break;
- }
- }
-
-
- OVR_FREE(devices);
-
- if (!device)
- {
- CFRelease(deviceSet);
- return false;
- }
-
- // Attempt to open device.
- if (IOHIDDeviceOpen(device, kIOHIDOptionsTypeSeizeDevice)
- != kIOReturnSuccess)
- {
- CFRelease(deviceSet);
- return false;
- }
-
- // Retain the device before we release the set.
- CFRetain(device);
- CFRelease(deviceSet);
-
-
- Device = device;
-
-
- if (!initInfo())
- {
- IOHIDDeviceClose(Device, kIOHIDOptionsTypeSeizeDevice);
- CFRelease(Device);
- Device = NULL;
- return false;
- }
-
-
- // Setup the Run Loop and callbacks.
- IOHIDDeviceScheduleWithRunLoop(Device,
- HIDManager->getRunLoop(),
- kCFRunLoopDefaultMode);
-
- IOHIDDeviceRegisterInputReportCallback(Device,
- ReadBuffer,
- ReadBufferSize,
- staticHIDReportCallback,
- this);
-
- IOHIDDeviceRegisterRemovalCallback(Device,
- staticDeviceRemovedCallback,
- this);
-
- return true;
-}
-
-void HIDDevice::HIDShutdown()
-{
-
- HIDManager->DevManager->pThread->RemoveTicksNotifier(this);
-
- if (Device != NULL) // Device may already have been closed if unplugged.
- {
- closeDevice(false);
- }
-
- IOObjectRelease(RepluggedNotification);
- if (RepluggedNotificationPort)
- IONotificationPortDestroy(RepluggedNotificationPort);
-
- LogText("OVR::OSX::HIDDevice - HIDShutdown '%s'\n", DevDesc.Path.ToCStr());
-}
-
-bool HIDDevice::setupDevicePluggedInNotification()
-{
-
- // Setup notification when devices are plugged in.
- RepluggedNotificationPort = IONotificationPortCreate(kIOMasterPortDefault);
-
- CFRunLoopSourceRef notificationRunLoopSource =
- IONotificationPortGetRunLoopSource(RepluggedNotificationPort);
-
- CFRunLoopAddSource(HIDManager->getRunLoop(),
- notificationRunLoopSource,
- kCFRunLoopDefaultMode);
-
- CFMutableDictionaryRef matchingDict = IOServiceMatching(kIOUSBDeviceClassName);
-
- // Have to specify vendorId and productId. Doesn't seem to accept additional
- // things like serial number.
- SInt32 vendorId = DevDesc.VendorId;
- CFNumberRef numberRef = CFNumberCreate(kCFAllocatorDefault,
- kCFNumberSInt32Type,
- &vendorId);
- CFDictionarySetValue(matchingDict, CFSTR(kUSBVendorID), numberRef);
- CFRelease(numberRef);
-
- SInt32 deviceProductId = DevDesc.ProductId;
- numberRef = CFNumberCreate(kCFAllocatorDefault,
- kCFNumberSInt32Type,
- &deviceProductId);
- CFDictionarySetValue(matchingDict, CFSTR(kUSBProductID), numberRef);
- CFRelease(numberRef);
-
- kern_return_t result =
- IOServiceAddMatchingNotification(RepluggedNotificationPort,
- kIOMatchedNotification,
- matchingDict,
- staticDeviceAddedCallback,
- this,
- &RepluggedNotification);
-
- if (result != KERN_SUCCESS)
- {
- CFRelease(RepluggedNotificationPort);
- RepluggedNotificationPort = 0;
- return false;
- }
-
- // Iterate through to arm.
- while (IOIteratorNext(RepluggedNotification))
- {
- }
-
- return true;
-}
-
-void HIDDevice::closeDevice(bool wasUnplugged)
-{
- OVR_ASSERT(Device != NULL);
-
- if (!wasUnplugged)
- {
- // Clear the registered callbacks.
- IOHIDDeviceRegisterInputReportCallback(Device,
- ReadBuffer,
- InputReportBufferLength,
- NULL,
- this);
-
- IOHIDDeviceRegisterRemovalCallback(Device, NULL, this);
-
- IOHIDDeviceUnscheduleFromRunLoop(Device,
- HIDManager->getRunLoop(),
- kCFRunLoopDefaultMode);
- IOHIDDeviceClose(Device, kIOHIDOptionsTypeNone);
- }
-
- CFRelease(Device);
- Device = NULL;
-
- LogText("OVR::OSX::HIDDevice - HID Device Closed '%s'\n", DevDesc.Path.ToCStr());
-}
-
-void HIDDevice::staticHIDReportCallback(void* pContext,
- IOReturn result,
- void* pSender,
- IOHIDReportType reportType,
- uint32_t reportId,
- uint8_t* pReport,
- CFIndex reportLength)
-{
- HIDDevice* pDevice = (HIDDevice*) pContext;
- return pDevice->hidReportCallback(pReport, (UInt32)reportLength);
-}
-
-void HIDDevice::hidReportCallback(UByte* pData, UInt32 length)
-{
-
- // We got data.
- if (Handler)
- {
- Handler->OnInputReport(pData, length);
- }
-}
-
-void HIDDevice::staticDeviceRemovedCallback(void* pContext, IOReturn result, void* pSender)
-{
- HIDDevice* pDevice = (HIDDevice*) pContext;
- pDevice->deviceRemovedCallback();
-}
-
-void HIDDevice::deviceRemovedCallback()
-{
- Ptr<HIDDevice> _this(this); // prevent from release
-
- Ptr<DeviceCreateDesc> existingHIDDev = HIDManager->DevManager->FindHIDDevice(DevDesc);
- if (existingHIDDev && existingHIDDev->pDevice)
- {
- HIDManager->DevManager->CallOnDeviceRemoved(existingHIDDev);
- }
- closeDevice(true);
-}
-
-CFStringRef HIDDevice::generateRunLoopModeString(IOHIDDeviceRef device)
-{
- const UInt32 safeBuffSize = 256;
- char nameBuff[safeBuffSize];
- OVR_sprintf(nameBuff, safeBuffSize, "%016lX", device);
-
- return CFStringCreateWithCString(NULL, nameBuff, kCFStringEncodingASCII);
-}
-
-bool HIDDevice::SetFeatureReport(UByte* data, UInt32 length)
-{
-
- if (!Device)
- return false;
-
- UByte reportID = data[0];
-
- if (reportID == 0)
- {
- // Not using reports so remove from data packet.
- data++;
- length--;
- }
-
- IOReturn result = IOHIDDeviceSetReport( Device,
- kIOHIDReportTypeFeature,
- reportID,
- data,
- length);
-
- return (result == kIOReturnSuccess);
-}
-
-bool HIDDevice::GetFeatureReport(UByte* data, UInt32 length)
-{
- if (!Device)
- return false;
-
- CFIndex bufferLength = length;
-
- // Report id is in first byte of the buffer.
- IOReturn result = IOHIDDeviceGetReport(Device, kIOHIDReportTypeFeature, data[0], data, &bufferLength);
-
- return (result == kIOReturnSuccess);
-}
-
-UInt64 HIDDevice::OnTicks(UInt64 ticksMks)
-{
-
- if (Handler)
- {
- return Handler->OnTicks(ticksMks);
- }
-
- return DeviceManagerThread::Notifier::OnTicks(ticksMks);
-}
-
-HIDDeviceManager* HIDDeviceManager::CreateInternal(OSX::DeviceManager* devManager)
-{
-
- if (!System::IsInitialized())
- {
- // Use custom message, since Log is not yet installed.
- OVR_DEBUG_STATEMENT(Log::GetDefaultLog()->
- LogMessage(Log_Debug, "HIDDeviceManager::Create failed - OVR::System not initialized"); );
- return 0;
- }
-
- Ptr<OSX::HIDDeviceManager> manager = *new OSX::HIDDeviceManager(devManager);
-
- if (manager)
- {
- if (manager->Initialize())
- {
- manager->AddRef();
- }
- else
- {
- manager.Clear();
- }
- }
-
- return manager.GetPtr();
-}
-
-} // namespace OSX
-
-//-------------------------------------------------------------------------------------
-// ***** Creation
-
-// Creates a new HIDDeviceManager and initializes OVR.
-HIDDeviceManager* HIDDeviceManager::Create()
-{
- OVR_ASSERT_LOG(false, ("Standalone mode not implemented yet."));
-
- if (!System::IsInitialized())
- {
- // Use custom message, since Log is not yet installed.
- OVR_DEBUG_STATEMENT(Log::GetDefaultLog()->
- LogMessage(Log_Debug, "HIDDeviceManager::Create failed - OVR::System not initialized"); );
- return 0;
- }
-
- Ptr<OSX::HIDDeviceManager> manager = *new OSX::HIDDeviceManager(NULL);
-
- if (manager)
- {
- if (manager->Initialize())
- {
- manager->AddRef();
- }
- else
- {
- manager.Clear();
- }
- }
-
- return manager.GetPtr();
-}
-
-} // namespace OVR
+/************************************************************************************
+Filename : OVR_OSX_HIDDevice.cpp
+Content : OSX HID device implementation.
+Created : February 26, 2013
+Authors : Lee Cooper
+
+Copyright : Copyright 2013 Oculus VR, Inc. All Rights reserved.
+
+Use of this software is subject to the terms of the Oculus license
+agreement provided at the time of installation or download, or which
+otherwise accompanies this software in either electronic or hard copy form.
+
+*************************************************************************************/
+
+#include "OVR_OSX_HIDDevice.h"
+
+#include <IOKit/usb/IOUSBLib.h>
+
+namespace OVR { namespace OSX {
+
+static const UInt32 MAX_QUEUED_INPUT_REPORTS = 5;
+
+//-------------------------------------------------------------------------------------
+// **** OSX::DeviceManager
+
+HIDDeviceManager::HIDDeviceManager(DeviceManager* manager)
+ : DevManager(manager)
+{
+ HIDManager = NULL;
+}
+
+HIDDeviceManager::~HIDDeviceManager()
+{
+}
+
+CFRunLoopRef HIDDeviceManager::getRunLoop()
+{
+ if (DevManager != NULL)
+ {
+ return DevManager->pThread->GetRunLoop();
+ }
+
+ return CFRunLoopGetCurrent();
+}
+
+bool HIDDeviceManager::initializeManager()
+{
+ if (HIDManager != NULL)
+ {
+ return true;
+ }
+
+ HIDManager = IOHIDManagerCreate(kCFAllocatorDefault, kIOHIDOptionsTypeNone);
+
+ if (!HIDManager)
+ {
+ return false;
+ }
+
+ // Create a Matching Dictionary
+ CFMutableDictionaryRef matchDict =
+ CFDictionaryCreateMutable(kCFAllocatorDefault,
+ 2,
+ &kCFTypeDictionaryKeyCallBacks,
+ &kCFTypeDictionaryValueCallBacks);
+
+ // Specify a device manufacturer in the Matching Dictionary
+ UInt32 vendorId = Oculus_VendorId;
+ CFNumberRef vendorIdRef = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &vendorId);
+ CFDictionarySetValue(matchDict,
+ CFSTR(kIOHIDVendorIDKey),
+ vendorIdRef);
+ // Register the Matching Dictionary to the HID Manager
+ IOHIDManagerSetDeviceMatching(HIDManager, matchDict);
+ CFRelease(vendorIdRef);
+ CFRelease(matchDict);
+
+ // Register a callback for USB device detection with the HID Manager
+ IOHIDManagerRegisterDeviceMatchingCallback(HIDManager, &staticDeviceMatchingCallback, this);
+
+ IOHIDManagerScheduleWithRunLoop(HIDManager, getRunLoop(), kCFRunLoopDefaultMode);
+
+ return true;
+}
+
+bool HIDDeviceManager::Initialize()
+{
+ return initializeManager();
+}
+
+void HIDDeviceManager::Shutdown()
+{
+ OVR_ASSERT_LOG(HIDManager, ("Should have called 'Initialize' before 'Shutdown'."));
+ CFRelease(HIDManager);
+
+ LogText("OVR::OSX::HIDDeviceManager - shutting down.\n");
+}
+
+bool HIDDeviceManager::getIntProperty(IOHIDDeviceRef device, CFStringRef propertyName, SInt32* pResult)
+{
+
+ CFTypeRef ref = IOHIDDeviceGetProperty(device, propertyName);
+
+ if (!ref)
+ {
+ return false;
+ }
+
+ if (CFGetTypeID(ref) != CFNumberGetTypeID())
+ {
+ return false;
+ }
+
+ CFNumberGetValue((CFNumberRef) ref, kCFNumberSInt32Type, pResult);
+
+ return true;
+}
+
+bool HIDDeviceManager::initVendorProductVersion(IOHIDDeviceRef device, HIDDeviceDesc* pDevDesc)
+{
+
+ if (!getVendorId(device, &(pDevDesc->VendorId)))
+ {
+ return false;
+ }
+
+ if (!getProductId(device, &(pDevDesc->ProductId)))
+ {
+ return false;
+ }
+
+ return true;
+}
+
+bool HIDDeviceManager::initUsage(IOHIDDeviceRef device, HIDDeviceDesc* pDevDesc)
+{
+
+ SInt32 result;
+
+ if (!getIntProperty(device, CFSTR(kIOHIDPrimaryUsagePageKey), &result))
+ {
+ return false;
+ }
+
+ pDevDesc->UsagePage = result;
+
+
+ if (!getIntProperty(device, CFSTR(kIOHIDPrimaryUsageKey), &result))
+ {
+ return false;
+ }
+
+ pDevDesc->Usage = result;
+
+ return true;
+}
+
+bool HIDDeviceManager::initSerialNumber(IOHIDDeviceRef device, HIDDeviceDesc* pDevDesc)
+{
+ return getSerialNumberString(device, &(pDevDesc->SerialNumber));
+}
+
+bool HIDDeviceManager::initStrings(IOHIDDeviceRef device, HIDDeviceDesc* pDevDesc)
+{
+
+ // Regardless of whether they fail we'll try and get the remaining.
+ getStringProperty(device, CFSTR(kIOHIDManufacturerKey), &(pDevDesc->Manufacturer));
+ getStringProperty(device, CFSTR(kIOHIDProductKey), &(pDevDesc->Product));
+
+ return true;
+}
+
+bool HIDDeviceManager::getStringProperty(IOHIDDeviceRef device,
+ CFStringRef propertyName,
+ String* pResult)
+{
+
+ CFStringRef str = (CFStringRef) IOHIDDeviceGetProperty(device, propertyName);
+
+ if (!str)
+ {
+ return false;
+ }
+
+ CFIndex length = CFStringGetLength(str);
+ CFRange range = CFRangeMake(0, length);
+
+ // Test the conversion first to get required buffer size.
+ CFIndex bufferLength;
+ CFIndex numberOfChars = CFStringGetBytes(str,
+ range,
+ kCFStringEncodingUTF8,
+ (char) '?',
+ FALSE,
+ NULL,
+ 0,
+ &bufferLength);
+
+ if (numberOfChars == 0)
+ {
+ return false;
+ }
+
+ // Now allocate buffer.
+ char* buffer = new char[bufferLength+1];
+
+ numberOfChars = CFStringGetBytes(str,
+ range,
+ kCFStringEncodingUTF8,
+ (char) '?',
+ FALSE,
+ (UInt8*) buffer,
+ bufferLength,
+ NULL);
+ OVR_ASSERT_LOG(numberOfChars != 0, ("CFStringGetBytes failed."));
+
+ buffer[bufferLength] = '\0';
+ *pResult = String(buffer);
+
+ return true;
+}
+
+bool HIDDeviceManager::getVendorId(IOHIDDeviceRef device, UInt16* pResult)
+{
+ SInt32 result;
+
+ if (!getIntProperty(device, CFSTR(kIOHIDVendorIDKey), &result))
+ {
+ return false;
+ }
+
+ *pResult = result;
+
+ return true;
+}
+
+bool HIDDeviceManager::getProductId(IOHIDDeviceRef device, UInt16* pResult)
+{
+ SInt32 result;
+
+ if (!getIntProperty(device, CFSTR(kIOHIDProductIDKey), &result))
+ {
+ return false;
+ }
+
+ *pResult = result;
+
+ return true;
+}
+
+bool HIDDeviceManager::getLocationId(IOHIDDeviceRef device, SInt32* pResult)
+{
+ SInt32 result;
+
+ if (!getIntProperty(device, CFSTR(kIOHIDLocationIDKey), &result))
+ {
+ return false;
+ }
+
+ *pResult = result;
+
+ return true;
+}
+
+bool HIDDeviceManager::getSerialNumberString(IOHIDDeviceRef device, String* pResult)
+{
+
+ if (!getStringProperty(device, CFSTR(kIOHIDSerialNumberKey), pResult))
+ {
+ return false;
+ }
+
+ return true;
+}
+
+bool HIDDeviceManager::getPath(IOHIDDeviceRef device, String* pPath)
+{
+
+ String transport;
+ if (!getStringProperty(device, CFSTR(kIOHIDTransportKey), &transport))
+ {
+ return false;
+ }
+
+ UInt16 vendorId;
+ if (!getVendorId(device, &vendorId))
+ {
+ return false;
+ }
+
+ UInt16 productId;
+ if (!getProductId(device, &productId))
+ {
+ return false;
+ }
+
+ String serialNumber;
+ if (!getSerialNumberString(device, &serialNumber))
+ {
+ return false;
+ }
+
+
+ StringBuffer buffer;
+ buffer.AppendFormat("%s:vid=%04hx:pid=%04hx:ser=%s",
+ transport.ToCStr(),
+ vendorId,
+ productId,
+ serialNumber.ToCStr());
+
+ *pPath = String(buffer);
+
+ return true;
+}
+
+bool HIDDeviceManager::Enumerate(HIDEnumerateVisitor* enumVisitor)
+{
+ if (!initializeManager())
+ {
+ return false;
+ }
+
+
+ CFSetRef deviceSet = IOHIDManagerCopyDevices(HIDManager);
+ if (!deviceSet)
+ return false;
+
+ CFIndex deviceCount = CFSetGetCount(deviceSet);
+
+ // Allocate a block of memory and read the set into it.
+ IOHIDDeviceRef* devices = (IOHIDDeviceRef*) OVR_ALLOC(sizeof(IOHIDDeviceRef) * deviceCount);
+ CFSetGetValues(deviceSet, (const void **) devices);
+
+
+ // Iterate over devices.
+ for (CFIndex deviceIndex = 0; deviceIndex < deviceCount; deviceIndex++)
+ {
+ IOHIDDeviceRef hidDev = devices[deviceIndex];
+
+ if (!hidDev)
+ {
+ continue;
+ }
+
+ HIDDeviceDesc devDesc;
+
+ if (getPath(hidDev, &(devDesc.Path)) &&
+ initVendorProductVersion(hidDev, &devDesc) &&
+ enumVisitor->MatchVendorProduct(devDesc.VendorId, devDesc.ProductId) &&
+ initUsage(hidDev, &devDesc))
+ {
+ initStrings(hidDev, &devDesc);
+ initSerialNumber(hidDev, &devDesc);
+
+ // Look for the device to check if it is already opened.
+ Ptr<DeviceCreateDesc> existingDevice = DevManager->FindHIDDevice(devDesc);
+ // if device exists and it is opened then most likely the CreateHIDFile
+ // will fail; therefore, we just set Enumerated to 'true' and continue.
+ if (existingDevice && existingDevice->pDevice)
+ {
+ existingDevice->Enumerated = true;
+ continue;
+ }
+
+ // Construct minimal device that the visitor callback can get feature reports from.
+ OSX::HIDDevice device(this, hidDev);
+
+ enumVisitor->Visit(device, devDesc);
+ }
+ }
+
+ OVR_FREE(devices);
+ CFRelease(deviceSet);
+
+ return true;
+}
+
+OVR::HIDDevice* HIDDeviceManager::Open(const String& path)
+{
+
+ Ptr<OSX::HIDDevice> device = *new OSX::HIDDevice(this);
+
+ if (!device->HIDInitialize(path))
+ {
+ return NULL;
+ }
+
+ device->AddRef();
+
+ return device;
+}
+
+bool HIDDeviceManager::getFullDesc(IOHIDDeviceRef device, HIDDeviceDesc* desc)
+{
+
+ if (!initVendorProductVersion(device, desc))
+ {
+ return false;
+ }
+
+ if (!initUsage(device, desc))
+ {
+ return false;
+ }
+
+ if (!initSerialNumber(device, desc))
+ {
+ return false;
+ }
+
+ initStrings(device, desc);
+
+ return true;
+}
+
+// New USB device specified in the matching dictionary has been added (callback function)
+void HIDDeviceManager::staticDeviceMatchingCallback(void *inContext,
+ IOReturn inResult,
+ void *inSender,
+ IOHIDDeviceRef inIOHIDDeviceRef)
+{
+ HIDDeviceManager* hidMgr = static_cast<HIDDeviceManager*>(inContext);
+ HIDDeviceDesc hidDevDesc;
+ hidMgr->getPath(inIOHIDDeviceRef, &hidDevDesc.Path);
+ hidMgr->getFullDesc(inIOHIDDeviceRef, &hidDevDesc);
+
+ hidMgr->DevManager->DetectHIDDevice(hidDevDesc);
+}
+
+//-------------------------------------------------------------------------------------
+// **** OSX::HIDDevice
+
+HIDDevice::HIDDevice(HIDDeviceManager* manager)
+ : HIDManager(manager), InMinimalMode(false)
+{
+ Device = NULL;
+ RepluggedNotificationPort = 0;
+}
+
+// This is a minimal constructor used during enumeration for us to pass
+// a HIDDevice to the visit function (so that it can query feature reports).
+HIDDevice::HIDDevice(HIDDeviceManager* manager, IOHIDDeviceRef device)
+: HIDManager(manager), Device(device), InMinimalMode(true)
+{
+ RepluggedNotificationPort = 0;
+}
+
+HIDDevice::~HIDDevice()
+{
+ if (!InMinimalMode)
+ {
+ HIDShutdown();
+ }
+}
+
+bool HIDDevice::HIDInitialize(const String& path)
+{
+
+ DevDesc.Path = path;
+
+ if (!openDevice())
+ {
+ LogText("OVR::OSX::HIDDevice - Failed to open HIDDevice: %s", path.ToCStr());
+ return false;
+ }
+
+ // Setup notification for when a device is unplugged and plugged back in.
+ if (!setupDevicePluggedInNotification())
+ {
+ LogText("OVR::OSX::HIDDevice - Failed to setup notification for when device plugged back in.");
+ closeDevice(false);
+ return false;
+ }
+
+ HIDManager->DevManager->pThread->AddTicksNotifier(this);
+
+
+ LogText("OVR::OSX::HIDDevice - Opened '%s'\n"
+ " Manufacturer:'%s' Product:'%s' Serial#:'%s'\n",
+ DevDesc.Path.ToCStr(),
+ DevDesc.Manufacturer.ToCStr(), DevDesc.Product.ToCStr(),
+ DevDesc.SerialNumber.ToCStr());
+
+ return true;
+}
+
+bool HIDDevice::initInfo()
+{
+ // Device must have been successfully opened.
+ OVR_ASSERT(Device);
+
+
+ // Get report lengths.
+ SInt32 bufferLength;
+ bool getResult = HIDManager->getIntProperty(Device, CFSTR(kIOHIDMaxInputReportSizeKey), &bufferLength);
+ OVR_ASSERT(getResult);
+ InputReportBufferLength = (UInt16) bufferLength;
+
+ getResult = HIDManager->getIntProperty(Device, CFSTR(kIOHIDMaxOutputReportSizeKey), &bufferLength);
+ OVR_ASSERT(getResult);
+ OutputReportBufferLength = (UInt16) bufferLength;
+
+ getResult = HIDManager->getIntProperty(Device, CFSTR(kIOHIDMaxFeatureReportSizeKey), &bufferLength);
+ OVR_ASSERT(getResult);
+ FeatureReportBufferLength = (UInt16) bufferLength;
+
+
+ if (ReadBufferSize < InputReportBufferLength)
+ {
+ OVR_ASSERT_LOG(false, ("Input report buffer length is bigger than read buffer."));
+ return false;
+ }
+
+ // Get device desc.
+ if (!HIDManager->getFullDesc(Device, &DevDesc))
+ {
+ OVR_ASSERT_LOG(false, ("Failed to get device desc while initializing device."));
+ return false;
+ }
+
+ return true;
+}
+
+void HIDDevice::staticDeviceAddedCallback(void* pContext, io_iterator_t iterator)
+{
+ HIDDevice* pDevice = (HIDDevice*) pContext;
+ pDevice->deviceAddedCallback(iterator);
+}
+
+void HIDDevice::deviceAddedCallback(io_iterator_t iterator)
+{
+
+ if (Device == NULL)
+ {
+ if (openDevice())
+ {
+ LogText("OVR::OSX::HIDDevice - Reopened device : %s", DevDesc.Path.ToCStr());
+
+ Ptr<DeviceCreateDesc> existingHIDDev = HIDManager->DevManager->FindHIDDevice(DevDesc);
+ if (existingHIDDev && existingHIDDev->pDevice)
+ {
+ HIDManager->DevManager->CallOnDeviceAdded(existingHIDDev);
+ }
+ }
+ }
+
+ // Reset callback.
+ while (IOIteratorNext(iterator))
+ ;
+}
+
+bool HIDDevice::openDevice()
+{
+
+ // Have to iterate through devices again to generate paths.
+ CFSetRef deviceSet = IOHIDManagerCopyDevices(HIDManager->HIDManager);
+ CFIndex deviceCount = CFSetGetCount(deviceSet);
+
+ // Allocate a block of memory and read the set into it.
+ IOHIDDeviceRef* devices = (IOHIDDeviceRef*) OVR_ALLOC(sizeof(IOHIDDeviceRef) * deviceCount);
+ CFSetGetValues(deviceSet, (const void **) devices);
+
+
+ // Iterate over devices.
+ IOHIDDeviceRef device = NULL;
+
+ for (CFIndex deviceIndex = 0; deviceIndex < deviceCount; deviceIndex++)
+ {
+ IOHIDDeviceRef tmpDevice = devices[deviceIndex];
+
+ if (!tmpDevice)
+ {
+ continue;
+ }
+
+ String path;
+ if (!HIDManager->getPath(tmpDevice, &path))
+ {
+ continue;
+ }
+
+ if (path == DevDesc.Path)
+ {
+ device = tmpDevice;
+ break;
+ }
+ }
+
+
+ OVR_FREE(devices);
+
+ if (!device)
+ {
+ CFRelease(deviceSet);
+ return false;
+ }
+
+ // Attempt to open device.
+ if (IOHIDDeviceOpen(device, kIOHIDOptionsTypeSeizeDevice)
+ != kIOReturnSuccess)
+ {
+ CFRelease(deviceSet);
+ return false;
+ }
+
+ // Retain the device before we release the set.
+ CFRetain(device);
+ CFRelease(deviceSet);
+
+
+ Device = device;
+
+
+ if (!initInfo())
+ {
+ IOHIDDeviceClose(Device, kIOHIDOptionsTypeSeizeDevice);
+ CFRelease(Device);
+ Device = NULL;
+ return false;
+ }
+
+
+ // Setup the Run Loop and callbacks.
+ IOHIDDeviceScheduleWithRunLoop(Device,
+ HIDManager->getRunLoop(),
+ kCFRunLoopDefaultMode);
+
+ IOHIDDeviceRegisterInputReportCallback(Device,
+ ReadBuffer,
+ ReadBufferSize,
+ staticHIDReportCallback,
+ this);
+
+ IOHIDDeviceRegisterRemovalCallback(Device,
+ staticDeviceRemovedCallback,
+ this);
+
+ return true;
+}
+
+void HIDDevice::HIDShutdown()
+{
+
+ HIDManager->DevManager->pThread->RemoveTicksNotifier(this);
+
+ if (Device != NULL) // Device may already have been closed if unplugged.
+ {
+ closeDevice(false);
+ }
+
+ IOObjectRelease(RepluggedNotification);
+ if (RepluggedNotificationPort)
+ IONotificationPortDestroy(RepluggedNotificationPort);
+
+ LogText("OVR::OSX::HIDDevice - HIDShutdown '%s'\n", DevDesc.Path.ToCStr());
+}
+
+bool HIDDevice::setupDevicePluggedInNotification()
+{
+
+ // Setup notification when devices are plugged in.
+ RepluggedNotificationPort = IONotificationPortCreate(kIOMasterPortDefault);
+
+ CFRunLoopSourceRef notificationRunLoopSource =
+ IONotificationPortGetRunLoopSource(RepluggedNotificationPort);
+
+ CFRunLoopAddSource(HIDManager->getRunLoop(),
+ notificationRunLoopSource,
+ kCFRunLoopDefaultMode);
+
+ CFMutableDictionaryRef matchingDict = IOServiceMatching(kIOUSBDeviceClassName);
+
+ // Have to specify vendorId and productId. Doesn't seem to accept additional
+ // things like serial number.
+ SInt32 vendorId = DevDesc.VendorId;
+ CFNumberRef numberRef = CFNumberCreate(kCFAllocatorDefault,
+ kCFNumberSInt32Type,
+ &vendorId);
+ CFDictionarySetValue(matchingDict, CFSTR(kUSBVendorID), numberRef);
+ CFRelease(numberRef);
+
+ SInt32 deviceProductId = DevDesc.ProductId;
+ numberRef = CFNumberCreate(kCFAllocatorDefault,
+ kCFNumberSInt32Type,
+ &deviceProductId);
+ CFDictionarySetValue(matchingDict, CFSTR(kUSBProductID), numberRef);
+ CFRelease(numberRef);
+
+ kern_return_t result =
+ IOServiceAddMatchingNotification(RepluggedNotificationPort,
+ kIOMatchedNotification,
+ matchingDict,
+ staticDeviceAddedCallback,
+ this,
+ &RepluggedNotification);
+
+ if (result != KERN_SUCCESS)
+ {
+ CFRelease(RepluggedNotificationPort);
+ RepluggedNotificationPort = 0;
+ return false;
+ }
+
+ // Iterate through to arm.
+ while (IOIteratorNext(RepluggedNotification))
+ {
+ }
+
+ return true;
+}
+
+void HIDDevice::closeDevice(bool wasUnplugged)
+{
+ OVR_ASSERT(Device != NULL);
+
+ if (!wasUnplugged)
+ {
+ // Clear the registered callbacks.
+ IOHIDDeviceRegisterInputReportCallback(Device,
+ ReadBuffer,
+ InputReportBufferLength,
+ NULL,
+ this);
+
+ IOHIDDeviceRegisterRemovalCallback(Device, NULL, this);
+
+ IOHIDDeviceUnscheduleFromRunLoop(Device,
+ HIDManager->getRunLoop(),
+ kCFRunLoopDefaultMode);
+ IOHIDDeviceClose(Device, kIOHIDOptionsTypeNone);
+ }
+
+ CFRelease(Device);
+ Device = NULL;
+
+ LogText("OVR::OSX::HIDDevice - HID Device Closed '%s'\n", DevDesc.Path.ToCStr());
+}
+
+void HIDDevice::staticHIDReportCallback(void* pContext,
+ IOReturn result,
+ void* pSender,
+ IOHIDReportType reportType,
+ uint32_t reportId,
+ uint8_t* pReport,
+ CFIndex reportLength)
+{
+ HIDDevice* pDevice = (HIDDevice*) pContext;
+ return pDevice->hidReportCallback(pReport, (UInt32)reportLength);
+}
+
+void HIDDevice::hidReportCallback(UByte* pData, UInt32 length)
+{
+
+ // We got data.
+ if (Handler)
+ {
+ Handler->OnInputReport(pData, length);
+ }
+}
+
+void HIDDevice::staticDeviceRemovedCallback(void* pContext, IOReturn result, void* pSender)
+{
+ HIDDevice* pDevice = (HIDDevice*) pContext;
+ pDevice->deviceRemovedCallback();
+}
+
+void HIDDevice::deviceRemovedCallback()
+{
+ Ptr<HIDDevice> _this(this); // prevent from release
+
+ Ptr<DeviceCreateDesc> existingHIDDev = HIDManager->DevManager->FindHIDDevice(DevDesc);
+ if (existingHIDDev && existingHIDDev->pDevice)
+ {
+ HIDManager->DevManager->CallOnDeviceRemoved(existingHIDDev);
+ }
+ closeDevice(true);
+}
+
+CFStringRef HIDDevice::generateRunLoopModeString(IOHIDDeviceRef device)
+{
+ const UInt32 safeBuffSize = 256;
+ char nameBuff[safeBuffSize];
+ OVR_sprintf(nameBuff, safeBuffSize, "%016lX", device);
+
+ return CFStringCreateWithCString(NULL, nameBuff, kCFStringEncodingASCII);
+}
+
+bool HIDDevice::SetFeatureReport(UByte* data, UInt32 length)
+{
+
+ if (!Device)
+ return false;
+
+ UByte reportID = data[0];
+
+ if (reportID == 0)
+ {
+ // Not using reports so remove from data packet.
+ data++;
+ length--;
+ }
+
+ IOReturn result = IOHIDDeviceSetReport( Device,
+ kIOHIDReportTypeFeature,
+ reportID,
+ data,
+ length);
+
+ return (result == kIOReturnSuccess);
+}
+
+bool HIDDevice::GetFeatureReport(UByte* data, UInt32 length)
+{
+ if (!Device)
+ return false;
+
+ CFIndex bufferLength = length;
+
+ // Report id is in first byte of the buffer.
+ IOReturn result = IOHIDDeviceGetReport(Device, kIOHIDReportTypeFeature, data[0], data, &bufferLength);
+
+ return (result == kIOReturnSuccess);
+}
+
+UInt64 HIDDevice::OnTicks(UInt64 ticksMks)
+{
+
+ if (Handler)
+ {
+ return Handler->OnTicks(ticksMks);
+ }
+
+ return DeviceManagerThread::Notifier::OnTicks(ticksMks);
+}
+
+HIDDeviceManager* HIDDeviceManager::CreateInternal(OSX::DeviceManager* devManager)
+{
+
+ if (!System::IsInitialized())
+ {
+ // Use custom message, since Log is not yet installed.
+ OVR_DEBUG_STATEMENT(Log::GetDefaultLog()->
+ LogMessage(Log_Debug, "HIDDeviceManager::Create failed - OVR::System not initialized"); );
+ return 0;
+ }
+
+ Ptr<OSX::HIDDeviceManager> manager = *new OSX::HIDDeviceManager(devManager);
+
+ if (manager)
+ {
+ if (manager->Initialize())
+ {
+ manager->AddRef();
+ }
+ else
+ {
+ manager.Clear();
+ }
+ }
+
+ return manager.GetPtr();
+}
+
+} // namespace OSX
+
+//-------------------------------------------------------------------------------------
+// ***** Creation
+
+// Creates a new HIDDeviceManager and initializes OVR.
+HIDDeviceManager* HIDDeviceManager::Create()
+{
+ OVR_ASSERT_LOG(false, ("Standalone mode not implemented yet."));
+
+ if (!System::IsInitialized())
+ {
+ // Use custom message, since Log is not yet installed.
+ OVR_DEBUG_STATEMENT(Log::GetDefaultLog()->
+ LogMessage(Log_Debug, "HIDDeviceManager::Create failed - OVR::System not initialized"); );
+ return 0;
+ }
+
+ Ptr<OSX::HIDDeviceManager> manager = *new OSX::HIDDeviceManager(NULL);
+
+ if (manager)
+ {
+ if (manager->Initialize())
+ {
+ manager->AddRef();
+ }
+ else
+ {
+ manager.Clear();
+ }
+ }
+
+ return manager.GetPtr();
+}
+
+} // namespace OVR
diff --git a/LibOVR/Src/OVR_OSX_HIDDevice.h b/LibOVR/Src/OVR_OSX_HIDDevice.h
index b9b3fc5..564bb60 100644
--- a/LibOVR/Src/OVR_OSX_HIDDevice.h
+++ b/LibOVR/Src/OVR_OSX_HIDDevice.h
@@ -1,149 +1,149 @@
-/************************************************************************************
-Filename : OVR_OSX_HIDDevice.h
-Content : OSX HID device implementation.
-Created : February 26, 2013
-Authors : Lee Cooper
-
-Copyright : Copyright 2013 Oculus VR, Inc. All Rights reserved.
-
-Use of this software is subject to the terms of the Oculus license
-agreement provided at the time of installation or download, or which
-otherwise accompanies this software in either electronic or hard copy form.
-
-*************************************************************************************/
-
-#ifndef OVR_OSX_HIDDevice_h
-#define OVR_OSX_HIDDevice_h
-
-#include "OVR_HIDDevice.h"
-
-#include "OVR_OSX_DeviceManager.h"
-
-#include <IOKit/IOKitLib.h>
-
-namespace OVR { namespace OSX {
-
-class HIDDeviceManager;
-
-//-------------------------------------------------------------------------------------
-// ***** OSX HIDDevice
-
-class HIDDevice : public OVR::HIDDevice, public DeviceManagerThread::Notifier
-{
-private:
- friend class HIDDeviceManager;
-
-public:
- HIDDevice(HIDDeviceManager* manager);
-
- // This is a minimal constructor used during enumeration for us to pass
- // a HIDDevice to the visit function (so that it can query feature reports).
- HIDDevice(HIDDeviceManager* manager, IOHIDDeviceRef device);
-
- virtual ~HIDDevice();
-
- bool HIDInitialize(const String& path);
- void HIDShutdown();
-
- virtual bool SetFeatureReport(UByte* data, UInt32 length);
- virtual bool GetFeatureReport(UByte* data, UInt32 length);
-
- bool Write(UByte* data, UInt32 length);
-
- bool Read(UByte* pData, UInt32 length, UInt32 timeoutMilliS);
- bool ReadBlocking(UByte* pData, UInt32 length);
-
-
- // DeviceManagerThread::Notifier
- UInt64 OnTicks(UInt64 ticksMks);
-
-private:
- bool initInfo();
- bool openDevice();
- void closeDevice(bool wasUnplugged);
- bool setupDevicePluggedInNotification();
- CFStringRef generateRunLoopModeString(IOHIDDeviceRef device);
-
- static void staticHIDReportCallback(void* pContext,
- IOReturn result,
- void* pSender,
- IOHIDReportType reportType,
- uint32_t reportId,
- uint8_t* pReport,
- CFIndex reportLength);
- void hidReportCallback(UByte* pData, UInt32 length);
-
- static void staticDeviceRemovedCallback(void* pContext,
- IOReturn result,
- void* pSender);
- void deviceRemovedCallback();
-
- static void staticDeviceAddedCallback(void* pContext,
- io_iterator_t iterator);
- void deviceAddedCallback(io_iterator_t iterator);
-
- bool InMinimalMode;
- HIDDeviceManager* HIDManager;
- IOHIDDeviceRef Device;
- HIDDeviceDesc DevDesc;
-
- enum { ReadBufferSize = 96 };
- UByte ReadBuffer[ReadBufferSize];
-
- UInt16 InputReportBufferLength;
- UInt16 OutputReportBufferLength;
- UInt16 FeatureReportBufferLength;
-
- IONotificationPortRef RepluggedNotificationPort;
- io_iterator_t RepluggedNotification;
-};
-
-
-//-------------------------------------------------------------------------------------
-// ***** OSX HIDDeviceManager
-
-class HIDDeviceManager : public OVR::HIDDeviceManager
-{
- friend class HIDDevice;
-
-public:
- HIDDeviceManager(OSX::DeviceManager* Manager);
- virtual ~HIDDeviceManager();
-
- virtual bool Initialize();
- virtual void Shutdown();
-
- virtual bool Enumerate(HIDEnumerateVisitor* enumVisitor);
- virtual OVR::HIDDevice* Open(const String& path);
-
- static HIDDeviceManager* CreateInternal(DeviceManager* manager);
-
-private:
- CFRunLoopRef getRunLoop();
- bool initializeManager();
- bool initVendorProductVersion(IOHIDDeviceRef device, HIDDeviceDesc* pDevDesc);
- bool initUsage(IOHIDDeviceRef device, HIDDeviceDesc* pDevDesc);
- bool initStrings(IOHIDDeviceRef device, HIDDeviceDesc* pDevDesc);
- bool initSerialNumber(IOHIDDeviceRef device, HIDDeviceDesc* pDevDesc);
- bool getVendorId(IOHIDDeviceRef device, UInt16* pResult);
- bool getProductId(IOHIDDeviceRef device, UInt16* pResult);
- bool getLocationId(IOHIDDeviceRef device, SInt32* pResult);
- bool getSerialNumberString(IOHIDDeviceRef device, String* pResult);
- bool getPath(IOHIDDeviceRef device, String* pPath);
- bool getIntProperty(IOHIDDeviceRef device, CFStringRef key, int32_t* pResult);
- bool getStringProperty(IOHIDDeviceRef device, CFStringRef propertyName, String* pResult);
- bool getFullDesc(IOHIDDeviceRef device, HIDDeviceDesc* desc);
-
- static void staticDeviceMatchingCallback(void *inContext,
- IOReturn inResult,
- void *inSender,
- IOHIDDeviceRef inIOHIDDeviceRef);
-
- DeviceManager* DevManager;
-
- IOHIDManagerRef HIDManager;
-};
-
-}} // namespace OVR::OSX
-
-#endif // OVR_OSX_HIDDevice_h
+/************************************************************************************
+Filename : OVR_OSX_HIDDevice.h
+Content : OSX HID device implementation.
+Created : February 26, 2013
+Authors : Lee Cooper
+
+Copyright : Copyright 2013 Oculus VR, Inc. All Rights reserved.
+
+Use of this software is subject to the terms of the Oculus license
+agreement provided at the time of installation or download, or which
+otherwise accompanies this software in either electronic or hard copy form.
+
+*************************************************************************************/
+
+#ifndef OVR_OSX_HIDDevice_h
+#define OVR_OSX_HIDDevice_h
+
+#include "OVR_HIDDevice.h"
+
+#include "OVR_OSX_DeviceManager.h"
+
+#include <IOKit/IOKitLib.h>
+
+namespace OVR { namespace OSX {
+
+class HIDDeviceManager;
+
+//-------------------------------------------------------------------------------------
+// ***** OSX HIDDevice
+
+class HIDDevice : public OVR::HIDDevice, public DeviceManagerThread::Notifier
+{
+private:
+ friend class HIDDeviceManager;
+
+public:
+ HIDDevice(HIDDeviceManager* manager);
+
+ // This is a minimal constructor used during enumeration for us to pass
+ // a HIDDevice to the visit function (so that it can query feature reports).
+ HIDDevice(HIDDeviceManager* manager, IOHIDDeviceRef device);
+
+ virtual ~HIDDevice();
+
+ bool HIDInitialize(const String& path);
+ void HIDShutdown();
+
+ virtual bool SetFeatureReport(UByte* data, UInt32 length);
+ virtual bool GetFeatureReport(UByte* data, UInt32 length);
+
+ bool Write(UByte* data, UInt32 length);
+
+ bool Read(UByte* pData, UInt32 length, UInt32 timeoutMilliS);
+ bool ReadBlocking(UByte* pData, UInt32 length);
+
+
+ // DeviceManagerThread::Notifier
+ UInt64 OnTicks(UInt64 ticksMks);
+
+private:
+ bool initInfo();
+ bool openDevice();
+ void closeDevice(bool wasUnplugged);
+ bool setupDevicePluggedInNotification();
+ CFStringRef generateRunLoopModeString(IOHIDDeviceRef device);
+
+ static void staticHIDReportCallback(void* pContext,
+ IOReturn result,
+ void* pSender,
+ IOHIDReportType reportType,
+ uint32_t reportId,
+ uint8_t* pReport,
+ CFIndex reportLength);
+ void hidReportCallback(UByte* pData, UInt32 length);
+
+ static void staticDeviceRemovedCallback(void* pContext,
+ IOReturn result,
+ void* pSender);
+ void deviceRemovedCallback();
+
+ static void staticDeviceAddedCallback(void* pContext,
+ io_iterator_t iterator);
+ void deviceAddedCallback(io_iterator_t iterator);
+
+ bool InMinimalMode;
+ HIDDeviceManager* HIDManager;
+ IOHIDDeviceRef Device;
+ HIDDeviceDesc DevDesc;
+
+ enum { ReadBufferSize = 96 };
+ UByte ReadBuffer[ReadBufferSize];
+
+ UInt16 InputReportBufferLength;
+ UInt16 OutputReportBufferLength;
+ UInt16 FeatureReportBufferLength;
+
+ IONotificationPortRef RepluggedNotificationPort;
+ io_iterator_t RepluggedNotification;
+};
+
+
+//-------------------------------------------------------------------------------------
+// ***** OSX HIDDeviceManager
+
+class HIDDeviceManager : public OVR::HIDDeviceManager
+{
+ friend class HIDDevice;
+
+public:
+ HIDDeviceManager(OSX::DeviceManager* Manager);
+ virtual ~HIDDeviceManager();
+
+ virtual bool Initialize();
+ virtual void Shutdown();
+
+ virtual bool Enumerate(HIDEnumerateVisitor* enumVisitor);
+ virtual OVR::HIDDevice* Open(const String& path);
+
+ static HIDDeviceManager* CreateInternal(DeviceManager* manager);
+
+private:
+ CFRunLoopRef getRunLoop();
+ bool initializeManager();
+ bool initVendorProductVersion(IOHIDDeviceRef device, HIDDeviceDesc* pDevDesc);
+ bool initUsage(IOHIDDeviceRef device, HIDDeviceDesc* pDevDesc);
+ bool initStrings(IOHIDDeviceRef device, HIDDeviceDesc* pDevDesc);
+ bool initSerialNumber(IOHIDDeviceRef device, HIDDeviceDesc* pDevDesc);
+ bool getVendorId(IOHIDDeviceRef device, UInt16* pResult);
+ bool getProductId(IOHIDDeviceRef device, UInt16* pResult);
+ bool getLocationId(IOHIDDeviceRef device, SInt32* pResult);
+ bool getSerialNumberString(IOHIDDeviceRef device, String* pResult);
+ bool getPath(IOHIDDeviceRef device, String* pPath);
+ bool getIntProperty(IOHIDDeviceRef device, CFStringRef key, int32_t* pResult);
+ bool getStringProperty(IOHIDDeviceRef device, CFStringRef propertyName, String* pResult);
+ bool getFullDesc(IOHIDDeviceRef device, HIDDeviceDesc* desc);
+
+ static void staticDeviceMatchingCallback(void *inContext,
+ IOReturn inResult,
+ void *inSender,
+ IOHIDDeviceRef inIOHIDDeviceRef);
+
+ DeviceManager* DevManager;
+
+ IOHIDManagerRef HIDManager;
+};
+
+}} // namespace OVR::OSX
+
+#endif // OVR_OSX_HIDDevice_h
diff --git a/LibOVR/Src/OVR_OSX_HMDDevice.cpp b/LibOVR/Src/OVR_OSX_HMDDevice.cpp
index df9003d..ee2899d 100644
--- a/LibOVR/Src/OVR_OSX_HMDDevice.cpp
+++ b/LibOVR/Src/OVR_OSX_HMDDevice.cpp
@@ -1,326 +1,400 @@
-/************************************************************************************
-
-Filename : OVR_OSX_HMDDevice.cpp
-Content : OSX Interface to HMD - detects HMD display
-Created : September 21, 2012
-Authors : Michael Antonov
-
-Copyright : Copyright 2012 Oculus VR, Inc. All Rights reserved.
-
-Use of this software is subject to the terms of the Oculus license
-agreement provided at the time of installation or download, or which
-otherwise accompanies this software in either electronic or hard copy form.
-
-*************************************************************************************/
-
-#include "OVR_OSX_HMDDevice.h"
-#include <CoreGraphics/CGDirectDisplay.h>
-#include <CoreGraphics/CGDisplayConfiguration.h>
-#include <CoreFoundation/CoreFoundation.h>
-#include <CoreFoundation/CFString.h>
-#include <IOKit/graphics/IOGraphicsLib.h>
-
-namespace OVR { namespace OSX {
-
-//-------------------------------------------------------------------------------------
-
-HMDDeviceCreateDesc::HMDDeviceCreateDesc(DeviceFactory* factory,
- UInt32 vend, UInt32 prod, const String& displayDeviceName, long dispId)
- : DeviceCreateDesc(factory, Device_HMD),
- DisplayDeviceName(displayDeviceName),
- DesktopX(0), DesktopY(0), Contents(0),
- HResolution(0), VResolution(0), HScreenSize(0), VScreenSize(0),
- DisplayId(dispId)
-{
- /* //??????????
- char idstring[9];
- idstring[0] = 'A'-1+((vend>>10) & 31);
- idstring[1] = 'A'-1+((vend>>5) & 31);
- idstring[2] = 'A'-1+((vend>>0) & 31);
- snprintf(idstring+3, 5, "%04d", prod);
- DeviceId = idstring;*/
- DeviceId = DisplayDeviceName;
-}
-
-HMDDeviceCreateDesc::HMDDeviceCreateDesc(const HMDDeviceCreateDesc& other)
- : DeviceCreateDesc(other.pFactory, Device_HMD),
- DeviceId(other.DeviceId), DisplayDeviceName(other.DisplayDeviceName),
- DesktopX(other.DesktopX), DesktopY(other.DesktopY), Contents(other.Contents),
- HResolution(other.HResolution), VResolution(other.VResolution),
- HScreenSize(other.HScreenSize), VScreenSize(other.VScreenSize),
- DisplayId(other.DisplayId)
-{
-}
-
-HMDDeviceCreateDesc::MatchResult HMDDeviceCreateDesc::MatchDevice(const DeviceCreateDesc& other,
- DeviceCreateDesc** pcandidate) const
-{
- if ((other.Type != Device_HMD) || (other.pFactory != pFactory))
- return Match_None;
-
- // There are several reasons we can come in here:
- // a) Matching this HMD Monitor created desc to OTHER HMD Monitor desc
- // - Require exact device DeviceId/DeviceName match
- // b) Matching SensorDisplayInfo created desc to OTHER HMD Monitor desc
- // - This DeviceId is empty; becomes candidate
- // c) Matching this HMD Monitor created desc to SensorDisplayInfo desc
- // - This other.DeviceId is empty; becomes candidate
-
- const HMDDeviceCreateDesc& s2 = (const HMDDeviceCreateDesc&) other;
-
- if ((DeviceId == s2.DeviceId) &&
- (DisplayId == s2.DisplayId))
- {
- // Non-null DeviceId may match while size is different if screen size was overwritten
- // by SensorDisplayInfo in prior iteration.
- if (!DeviceId.IsEmpty() ||
- ((HScreenSize == s2.HScreenSize) &&
- (VScreenSize == s2.VScreenSize)) )
- {
- *pcandidate = 0;
- return Match_Found;
- }
- }
-
-
- // DisplayInfo takes precedence, although we try to match it first.
- if ((HResolution == s2.HResolution) &&
- (VResolution == s2.VResolution) &&
- (HScreenSize == s2.HScreenSize) &&
- (VScreenSize == s2.VScreenSize))
- {
- if (DeviceId.IsEmpty() && !s2.DeviceId.IsEmpty())
- {
- *pcandidate = const_cast<DeviceCreateDesc*>((const DeviceCreateDesc*)this);
- return Match_Candidate;
- }
-
- *pcandidate = 0;
- return Match_Found;
- }
-
- // SensorDisplayInfo may override resolution settings, so store as candidiate.
- if (s2.DeviceId.IsEmpty() && s2.DisplayId == 0)
- {
- *pcandidate = const_cast<DeviceCreateDesc*>((const DeviceCreateDesc*)this);
- return Match_Candidate;
- }
- // OTHER HMD Monitor desc may initialize DeviceName/Id
- else if (DeviceId.IsEmpty() && DisplayId == 0)
- {
- *pcandidate = const_cast<DeviceCreateDesc*>((const DeviceCreateDesc*)this);
- return Match_Candidate;
- }
-
- return Match_None;
-}
-
-
-bool HMDDeviceCreateDesc::UpdateMatchedCandidate(const DeviceCreateDesc& other, bool* newDeviceFlag)
-{
- // This candidate was the the "best fit" to apply sensor DisplayInfo to.
- OVR_ASSERT(other.Type == Device_HMD);
-
- const HMDDeviceCreateDesc& s2 = (const HMDDeviceCreateDesc&) other;
-
- // Force screen size on resolution from SensorDisplayInfo.
- // We do this because USB detection is more reliable as compared to HDMI EDID,
- // which may be corrupted by splitter reporting wrong monitor
- if (s2.DeviceId.IsEmpty() && s2.DisplayId == 0)
- {
- // disconnected HMD: replace old descriptor by the 'fake' one.
- HScreenSize = s2.HScreenSize;
- VScreenSize = s2.VScreenSize;
- Contents |= Contents_Screen;
-
- if (s2.Contents & HMDDeviceCreateDesc::Contents_Distortion)
- {
- memcpy(DistortionK, s2.DistortionK, sizeof(float)*4);
- Contents |= Contents_Distortion;
- }
- DeviceId = s2.DeviceId;
- DisplayId = s2.DisplayId;
- DisplayDeviceName = s2.DisplayDeviceName;
- if (newDeviceFlag) *newDeviceFlag = true;
- }
- else if (DeviceId.IsEmpty())
- {
- // This branch is executed when 'fake' HMD descriptor is being replaced by
- // the real one.
- DeviceId = s2.DeviceId;
- DisplayId = s2.DisplayId;
- DisplayDeviceName = s2.DisplayDeviceName;
- if (newDeviceFlag) *newDeviceFlag = true;
- }
- else
- {
- if (newDeviceFlag) *newDeviceFlag = false;
- }
-
- return true;
-}
-
-
-//-------------------------------------------------------------------------------------
-
-
-//-------------------------------------------------------------------------------------
-// ***** HMDDeviceFactory
-
-HMDDeviceFactory HMDDeviceFactory::Instance;
-
-void HMDDeviceFactory::EnumerateDevices(EnumerateVisitor& visitor)
-{
- CGDirectDisplayID Displays[32];
- uint32_t NDisplays = 0;
- CGGetOnlineDisplayList(32, Displays, &NDisplays);
-
- for (int i = 0; i < NDisplays; i++)
- {
- io_service_t port = CGDisplayIOServicePort(Displays[i]);
- CFDictionaryRef DispInfo = IODisplayCreateInfoDictionary(port, kIODisplayMatchingInfo);
-
- uint32_t vendor = CGDisplayVendorNumber(Displays[i]);
- uint32_t product = CGDisplayModelNumber(Displays[i]);
- unsigned mwidth = (unsigned)CGDisplayPixelsWide(Displays[i]);
- unsigned mheight = (unsigned)CGDisplayPixelsHigh(Displays[i]);
- CGRect desktop = CGDisplayBounds(Displays[i]);
-
- if (vendor == 16082 && product == 1)
- {
- char idstring[9];
- idstring[0] = 'A'-1+((vendor>>10) & 31);
- idstring[1] = 'A'-1+((vendor>>5) & 31);
- idstring[2] = 'A'-1+((vendor>>0) & 31);
- snprintf(idstring+3, 5, "%04d", product);
-
- HMDDeviceCreateDesc hmdCreateDesc(this, vendor, product, idstring, Displays[i]);
-
- if (hmdCreateDesc.Is7Inch())
- {
- // Physical dimension of SLA screen.
- hmdCreateDesc.SetScreenParameters(desktop.origin.x, desktop.origin.y, mwidth, mheight, 0.14976f, 0.0936f);
- }
- else
- {
- hmdCreateDesc.SetScreenParameters(desktop.origin.x, desktop.origin.y, mwidth, mheight, 0.12096f, 0.0756f);
- }
- OVR_DEBUG_LOG_TEXT(("DeviceManager - HMD Found %x:%x\n", vendor, product));
-
- // Notify caller about detected device. This will call EnumerateAddDevice
- // if the this is the first time device was detected.
- visitor.Visit(hmdCreateDesc);
- }
- CFRelease(DispInfo);
- }
-}
-
-DeviceBase* HMDDeviceCreateDesc::NewDeviceInstance()
-{
- return new HMDDevice(this);
-}
-
-bool HMDDeviceCreateDesc::Is7Inch() const
-{
- return (strstr(DeviceId.ToCStr(), "OVR0001") != 0) || (Contents & Contents_7Inch);
-}
-
-bool HMDDeviceCreateDesc::GetDeviceInfo(DeviceInfo* info) const
-{
- if ((info->InfoClassType != Device_HMD) &&
- (info->InfoClassType != Device_None))
- return false;
-
- bool is7Inch = Is7Inch();
-
- OVR_strcpy(info->ProductName, DeviceInfo::MaxNameLength,
- is7Inch ? "Oculus Rift DK1" : "Oculus Rift DK1-Prototype");
- OVR_strcpy(info->Manufacturer, DeviceInfo::MaxNameLength, "Oculus VR");
- info->Type = Device_HMD;
- info->Version = 0;
-
- // Display detection.
- if (info->InfoClassType == Device_HMD)
- {
- HMDInfo* hmdInfo = static_cast<HMDInfo*>(info);
-
- hmdInfo->DesktopX = DesktopX;
- hmdInfo->DesktopY = DesktopY;
- hmdInfo->HResolution = HResolution;
- hmdInfo->VResolution = VResolution;
- hmdInfo->HScreenSize = HScreenSize;
- hmdInfo->VScreenSize = VScreenSize;
- hmdInfo->VScreenCenter = VScreenSize * 0.5f;
- hmdInfo->InterpupillaryDistance = 0.064f; // Default IPD; should be configurable.
- hmdInfo->LensSeparationDistance = 0.0635f;
-
- if (Contents & Contents_Distortion)
- {
- memcpy(hmdInfo->DistortionK, DistortionK, sizeof(float)*4);
- }
- else
- {
- if (is7Inch)
- {
- // 7" screen.
- hmdInfo->DistortionK[0] = 1.0f;
- hmdInfo->DistortionK[1] = 0.22f;
- hmdInfo->DistortionK[2] = 0.24f;
- hmdInfo->EyeToScreenDistance = 0.041f;
-
- hmdInfo->ChromaAbCorrection[0] = 0.996f;
- hmdInfo->ChromaAbCorrection[1] = -0.004f;
- hmdInfo->ChromaAbCorrection[2] = 1.014f;
- hmdInfo->ChromaAbCorrection[3] = 0.0f;
- }
- else
- {
- hmdInfo->DistortionK[0] = 1.0f;
- hmdInfo->DistortionK[1] = 0.18f;
- hmdInfo->DistortionK[2] = 0.115f;
- hmdInfo->EyeToScreenDistance = 0.0387f;
- }
- }
-
- OVR_strcpy(hmdInfo->DisplayDeviceName, sizeof(hmdInfo->DisplayDeviceName),
- DisplayDeviceName.ToCStr());
- hmdInfo->DisplayId = DisplayId;
- }
-
- return true;
-}
-
-//-------------------------------------------------------------------------------------
-// ***** HMDDevice
-
-HMDDevice::HMDDevice(HMDDeviceCreateDesc* createDesc)
- : OVR::DeviceImpl<OVR::HMDDevice>(createDesc, 0)
-{
-}
-HMDDevice::~HMDDevice()
-{
-}
-
-bool HMDDevice::Initialize(DeviceBase* parent)
-{
- pParent = parent;
- return true;
-}
-void HMDDevice::Shutdown()
-{
- pParent.Clear();
-}
-
-OVR::SensorDevice* HMDDevice::GetSensor()
-{
- // Just return first sensor found since we have no way to match it yet.
- OVR::SensorDevice* sensor = GetManager()->EnumerateDevices<SensorDevice>().CreateDevice();
- if (sensor)
- sensor->SetCoordinateFrame(SensorDevice::Coord_HMD);
- return sensor;
-}
-
-
-}} // namespace OVR::OSX
-
-
+/************************************************************************************
+
+Filename : OVR_OSX_HMDDevice.cpp
+Content : OSX Interface to HMD - detects HMD display
+Created : September 21, 2012
+Authors : Michael Antonov
+
+Copyright : Copyright 2012 Oculus VR, Inc. All Rights reserved.
+
+Use of this software is subject to the terms of the Oculus license
+agreement provided at the time of installation or download, or which
+otherwise accompanies this software in either electronic or hard copy form.
+
+*************************************************************************************/
+
+#include "OVR_OSX_HMDDevice.h"
+#include <CoreGraphics/CGDirectDisplay.h>
+#include <CoreGraphics/CGDisplayConfiguration.h>
+#include <CoreFoundation/CoreFoundation.h>
+#include <CoreFoundation/CFString.h>
+#include <IOKit/graphics/IOGraphicsLib.h>
+
+namespace OVR { namespace OSX {
+
+//-------------------------------------------------------------------------------------
+
+HMDDeviceCreateDesc::HMDDeviceCreateDesc(DeviceFactory* factory,
+ UInt32 vend, UInt32 prod, const String& displayDeviceName, long dispId)
+ : DeviceCreateDesc(factory, Device_HMD),
+ DisplayDeviceName(displayDeviceName),
+ DesktopX(0), DesktopY(0), Contents(0),
+ HResolution(0), VResolution(0), HScreenSize(0), VScreenSize(0),
+ DisplayId(dispId)
+{
+ /* //??????????
+ char idstring[9];
+ idstring[0] = 'A'-1+((vend>>10) & 31);
+ idstring[1] = 'A'-1+((vend>>5) & 31);
+ idstring[2] = 'A'-1+((vend>>0) & 31);
+ snprintf(idstring+3, 5, "%04d", prod);
+ DeviceId = idstring;*/
+ DeviceId = DisplayDeviceName;
+}
+
+HMDDeviceCreateDesc::HMDDeviceCreateDesc(const HMDDeviceCreateDesc& other)
+ : DeviceCreateDesc(other.pFactory, Device_HMD),
+ DeviceId(other.DeviceId), DisplayDeviceName(other.DisplayDeviceName),
+ DesktopX(other.DesktopX), DesktopY(other.DesktopY), Contents(other.Contents),
+ HResolution(other.HResolution), VResolution(other.VResolution),
+ HScreenSize(other.HScreenSize), VScreenSize(other.VScreenSize),
+ DisplayId(other.DisplayId)
+{
+}
+
+HMDDeviceCreateDesc::MatchResult HMDDeviceCreateDesc::MatchDevice(const DeviceCreateDesc& other,
+ DeviceCreateDesc** pcandidate) const
+{
+ if ((other.Type != Device_HMD) || (other.pFactory != pFactory))
+ return Match_None;
+
+ // There are several reasons we can come in here:
+ // a) Matching this HMD Monitor created desc to OTHER HMD Monitor desc
+ // - Require exact device DeviceId/DeviceName match
+ // b) Matching SensorDisplayInfo created desc to OTHER HMD Monitor desc
+ // - This DeviceId is empty; becomes candidate
+ // c) Matching this HMD Monitor created desc to SensorDisplayInfo desc
+ // - This other.DeviceId is empty; becomes candidate
+
+ const HMDDeviceCreateDesc& s2 = (const HMDDeviceCreateDesc&) other;
+
+ if ((DeviceId == s2.DeviceId) &&
+ (DisplayId == s2.DisplayId))
+ {
+ // Non-null DeviceId may match while size is different if screen size was overwritten
+ // by SensorDisplayInfo in prior iteration.
+ if (!DeviceId.IsEmpty() ||
+ ((HScreenSize == s2.HScreenSize) &&
+ (VScreenSize == s2.VScreenSize)) )
+ {
+ *pcandidate = 0;
+ return Match_Found;
+ }
+ }
+
+
+ // DisplayInfo takes precedence, although we try to match it first.
+ if ((HResolution == s2.HResolution) &&
+ (VResolution == s2.VResolution) &&
+ (HScreenSize == s2.HScreenSize) &&
+ (VScreenSize == s2.VScreenSize))
+ {
+ if (DeviceId.IsEmpty() && !s2.DeviceId.IsEmpty())
+ {
+ *pcandidate = const_cast<DeviceCreateDesc*>((const DeviceCreateDesc*)this);
+ return Match_Candidate;
+ }
+
+ *pcandidate = 0;
+ return Match_Found;
+ }
+
+ // SensorDisplayInfo may override resolution settings, so store as candidiate.
+ if (s2.DeviceId.IsEmpty() && s2.DisplayId == 0)
+ {
+ *pcandidate = const_cast<DeviceCreateDesc*>((const DeviceCreateDesc*)this);
+ return Match_Candidate;
+ }
+ // OTHER HMD Monitor desc may initialize DeviceName/Id
+ else if (DeviceId.IsEmpty() && DisplayId == 0)
+ {
+ *pcandidate = const_cast<DeviceCreateDesc*>((const DeviceCreateDesc*)this);
+ return Match_Candidate;
+ }
+
+ return Match_None;
+}
+
+
+bool HMDDeviceCreateDesc::UpdateMatchedCandidate(const DeviceCreateDesc& other, bool* newDeviceFlag)
+{
+ // This candidate was the the "best fit" to apply sensor DisplayInfo to.
+ OVR_ASSERT(other.Type == Device_HMD);
+
+ const HMDDeviceCreateDesc& s2 = (const HMDDeviceCreateDesc&) other;
+
+ // Force screen size on resolution from SensorDisplayInfo.
+ // We do this because USB detection is more reliable as compared to HDMI EDID,
+ // which may be corrupted by splitter reporting wrong monitor
+ if (s2.DeviceId.IsEmpty() && s2.DisplayId == 0)
+ {
+ // disconnected HMD: replace old descriptor by the 'fake' one.
+ HScreenSize = s2.HScreenSize;
+ VScreenSize = s2.VScreenSize;
+ Contents |= Contents_Screen;
+
+ if (s2.Contents & HMDDeviceCreateDesc::Contents_Distortion)
+ {
+ memcpy(DistortionK, s2.DistortionK, sizeof(float)*4);
+ Contents |= Contents_Distortion;
+ }
+ DeviceId = s2.DeviceId;
+ DisplayId = s2.DisplayId;
+ DisplayDeviceName = s2.DisplayDeviceName;
+ if (newDeviceFlag) *newDeviceFlag = true;
+ }
+ else if (DeviceId.IsEmpty())
+ {
+ // This branch is executed when 'fake' HMD descriptor is being replaced by
+ // the real one.
+ DeviceId = s2.DeviceId;
+ DisplayId = s2.DisplayId;
+ DisplayDeviceName = s2.DisplayDeviceName;
+ if (newDeviceFlag) *newDeviceFlag = true;
+ }
+ else
+ {
+ if (newDeviceFlag) *newDeviceFlag = false;
+ }
+
+ return true;
+}
+
+
+//-------------------------------------------------------------------------------------
+
+
+//-------------------------------------------------------------------------------------
+// ***** HMDDeviceFactory
+
+HMDDeviceFactory HMDDeviceFactory::Instance;
+
+void HMDDeviceFactory::EnumerateDevices(EnumerateVisitor& visitor)
+{
+ CGDirectDisplayID Displays[32];
+ uint32_t NDisplays = 0;
+ CGGetOnlineDisplayList(32, Displays, &NDisplays);
+
+ for (int i = 0; i < NDisplays; i++)
+ {
+ io_service_t port = CGDisplayIOServicePort(Displays[i]);
+ CFDictionaryRef DispInfo = IODisplayCreateInfoDictionary(port, kIODisplayMatchingInfo);
+
+ uint32_t vendor = CGDisplayVendorNumber(Displays[i]);
+ uint32_t product = CGDisplayModelNumber(Displays[i]);
+ unsigned mwidth = (unsigned)CGDisplayPixelsWide(Displays[i]);
+ unsigned mheight = (unsigned)CGDisplayPixelsHigh(Displays[i]);
+ CGRect desktop = CGDisplayBounds(Displays[i]);
+
+ if (vendor == 16082 && product == 1)
+ {
+ char idstring[9];
+ idstring[0] = 'A'-1+((vendor>>10) & 31);
+ idstring[1] = 'A'-1+((vendor>>5) & 31);
+ idstring[2] = 'A'-1+((vendor>>0) & 31);
+ snprintf(idstring+3, 5, "%04d", product);
+
+ HMDDeviceCreateDesc hmdCreateDesc(this, vendor, product, idstring, Displays[i]);
+
+ if (product == 2)
+ {
+ hmdCreateDesc.SetScreenParameters(desktop.origin.x, desktop.origin.y,
+ mwidth, mheight, 0.12096f, 0.06804f);
+ }
+ else
+ {
+ if (hmdCreateDesc.Is7Inch())
+ {
+ // Physical dimension of SLA screen.
+ hmdCreateDesc.SetScreenParameters(desktop.origin.x, desktop.origin.y,
+ mwidth, mheight, 0.14976f, 0.0936f);
+ }
+ else
+ {
+ hmdCreateDesc.SetScreenParameters(desktop.origin.x, desktop.origin.y,
+ mwidth, mheight, 0.12096f, 0.0756f);
+ }
+ }
+
+ OVR_DEBUG_LOG_TEXT(("DeviceManager - HMD Found %x:%x\n", vendor, product));
+
+ // Notify caller about detected device. This will call EnumerateAddDevice
+ // if the this is the first time device was detected.
+ visitor.Visit(hmdCreateDesc);
+ }
+ CFRelease(DispInfo);
+ }
+}
+
+DeviceBase* HMDDeviceCreateDesc::NewDeviceInstance()
+{
+ return new HMDDevice(this);
+}
+
+bool HMDDeviceCreateDesc::Is7Inch() const
+{
+ return (strstr(DeviceId.ToCStr(), "OVR0001") != 0) || (Contents & Contents_7Inch);
+}
+
+Profile* HMDDeviceCreateDesc::GetProfileAddRef() const
+{
+ // Create device may override profile name, so get it from there is possible.
+ ProfileManager* profileManager = GetManagerImpl()->GetProfileManager();
+ ProfileType profileType = GetProfileType();
+ const char * profileName = pDevice ?
+ ((HMDDevice*)pDevice)->GetProfileName() :
+ profileManager->GetDefaultProfileName(profileType);
+
+ return profileName ?
+ profileManager->LoadProfile(profileType, profileName) :
+ profileManager->GetDeviceDefaultProfile(profileType);
+}
+
+bool HMDDeviceCreateDesc::GetDeviceInfo(DeviceInfo* info) const
+{
+ if ((info->InfoClassType != Device_HMD) &&
+ (info->InfoClassType != Device_None))
+ return false;
+
+ bool is7Inch = Is7Inch();
+
+ OVR_strcpy(info->ProductName, DeviceInfo::MaxNameLength,
+ is7Inch ? "Oculus Rift DK1" :
+ ((HResolution >= 1920) ? "Oculus Rift DK HD" : "Oculus Rift DK1-Prototype") );
+ OVR_strcpy(info->Manufacturer, DeviceInfo::MaxNameLength, "Oculus VR");
+ info->Type = Device_HMD;
+ info->Version = 0;
+
+ // Display detection.
+ if (info->InfoClassType == Device_HMD)
+ {
+ HMDInfo* hmdInfo = static_cast<HMDInfo*>(info);
+
+ hmdInfo->DesktopX = DesktopX;
+ hmdInfo->DesktopY = DesktopY;
+ hmdInfo->HResolution = HResolution;
+ hmdInfo->VResolution = VResolution;
+ hmdInfo->HScreenSize = HScreenSize;
+ hmdInfo->VScreenSize = VScreenSize;
+ hmdInfo->VScreenCenter = VScreenSize * 0.5f;
+ hmdInfo->InterpupillaryDistance = 0.064f; // Default IPD; should be configurable.
+ hmdInfo->LensSeparationDistance = 0.0635f;
+
+ // Obtain IPD from profile.
+ Ptr<Profile> profile = *GetProfileAddRef();
+
+ if (profile)
+ {
+ hmdInfo->InterpupillaryDistance = profile->GetIPD();
+ // TBD: Switch on EyeCup type.
+ }
+
+ if (Contents & Contents_Distortion)
+ {
+ memcpy(hmdInfo->DistortionK, DistortionK, sizeof(float)*4);
+ }
+ else
+ {
+ if (is7Inch)
+ {
+ // 7" screen.
+ hmdInfo->DistortionK[0] = 1.0f;
+ hmdInfo->DistortionK[1] = 0.22f;
+ hmdInfo->DistortionK[2] = 0.24f;
+ hmdInfo->EyeToScreenDistance = 0.041f;
+ }
+ else
+ {
+ hmdInfo->DistortionK[0] = 1.0f;
+ hmdInfo->DistortionK[1] = 0.18f;
+ hmdInfo->DistortionK[2] = 0.115f;
+
+ if (HResolution == 1920)
+ hmdInfo->EyeToScreenDistance = 0.040f;
+ else
+ hmdInfo->EyeToScreenDistance = 0.0387f;
+ }
+
+ hmdInfo->ChromaAbCorrection[0] = 0.996f;
+ hmdInfo->ChromaAbCorrection[1] = -0.004f;
+ hmdInfo->ChromaAbCorrection[2] = 1.014f;
+ hmdInfo->ChromaAbCorrection[3] = 0.0f;
+ }
+
+ OVR_strcpy(hmdInfo->DisplayDeviceName, sizeof(hmdInfo->DisplayDeviceName),
+ DisplayDeviceName.ToCStr());
+ hmdInfo->DisplayId = DisplayId;
+ }
+
+ return true;
+}
+
+//-------------------------------------------------------------------------------------
+// ***** HMDDevice
+
+HMDDevice::HMDDevice(HMDDeviceCreateDesc* createDesc)
+ : OVR::DeviceImpl<OVR::HMDDevice>(createDesc, 0)
+{
+}
+HMDDevice::~HMDDevice()
+{
+}
+
+bool HMDDevice::Initialize(DeviceBase* parent)
+{
+ pParent = parent;
+
+ // Initialize user profile to default for device.
+ ProfileManager* profileManager = GetManager()->GetProfileManager();
+ ProfileName = profileManager->GetDefaultProfileName(getDesc()->GetProfileType());
+
+ return true;
+}
+void HMDDevice::Shutdown()
+{
+ ProfileName.Clear();
+ pCachedProfile.Clear();
+ pParent.Clear();
+}
+
+Profile* HMDDevice::GetProfile() const
+{
+ if (!pCachedProfile)
+ pCachedProfile = *getDesc()->GetProfileAddRef();
+ return pCachedProfile.GetPtr();
+}
+
+const char* HMDDevice::GetProfileName() const
+{
+ return ProfileName.ToCStr();
+}
+
+bool HMDDevice::SetProfileName(const char* name)
+{
+ pCachedProfile.Clear();
+ if (!name)
+ {
+ ProfileName.Clear();
+ return 0;
+ }
+ if (GetManager()->GetProfileManager()->HasProfile(getDesc()->GetProfileType(), name))
+ {
+ ProfileName = name;
+ return true;
+ }
+ return false;
+}
+
+OVR::SensorDevice* HMDDevice::GetSensor()
+{
+ // Just return first sensor found since we have no way to match it yet.
+ OVR::SensorDevice* sensor = GetManager()->EnumerateDevices<SensorDevice>().CreateDevice();
+ if (sensor)
+ sensor->SetCoordinateFrame(SensorDevice::Coord_HMD);
+ return sensor;
+}
+
+
+}} // namespace OVR::OSX
+
+
diff --git a/LibOVR/Src/OVR_OSX_HMDDevice.h b/LibOVR/Src/OVR_OSX_HMDDevice.h
index 37c34ed..52b8471 100644
--- a/LibOVR/Src/OVR_OSX_HMDDevice.h
+++ b/LibOVR/Src/OVR_OSX_HMDDevice.h
@@ -1,136 +1,160 @@
-/************************************************************************************
-
-Filename : OVR_OSX_HMDDevice.h
-Content : OSX HMDDevice implementation
-Created : September 21, 2012
-Authors : Michael Antonov
-
-Copyright : Copyright 2012 Oculus VR, Inc. All Rights reserved.
-
-Use of this software is subject to the terms of the Oculus license
-agreement provided at the time of installation or download, or which
-otherwise accompanies this software in either electronic or hard copy form.
-
-*************************************************************************************/
-
-#ifndef OVR_OSX_HMDDevice_h
-#define OVR_OSX_HMDDevice_h
-
-#include "OVR_DeviceImpl.h"
-#include <Kernel/OVR_String.h>
-
-namespace OVR { namespace OSX {
-
-class HMDDevice;
-
-
-//-------------------------------------------------------------------------------------
-
-// HMDDeviceFactory enumerates attached Oculus HMD devices.
-//
-// This is currently done by matching monitor device strings.
-
-class HMDDeviceFactory : public DeviceFactory
-{
-public:
- static HMDDeviceFactory Instance;
-
- // Enumerates devices, creating and destroying relevant objects in manager.
- virtual void EnumerateDevices(EnumerateVisitor& visitor);
-
-protected:
- DeviceManager* getManager() const { return (DeviceManager*) pManager; }
-};
-
-
-class HMDDeviceCreateDesc : public DeviceCreateDesc
-{
- friend class HMDDevice;
-
-protected:
- enum
- {
- Contents_Screen = 1,
- Contents_Distortion = 2,
- Contents_7Inch = 4,
- };
-
-public:
-
- HMDDeviceCreateDesc(DeviceFactory* factory,
- UInt32 vendor, UInt32 product, const String& displayDeviceName, long dispId);
- HMDDeviceCreateDesc(const HMDDeviceCreateDesc& other);
-
- virtual DeviceCreateDesc* Clone() const
- {
- return new HMDDeviceCreateDesc(*this);
- }
-
- virtual DeviceBase* NewDeviceInstance();
-
- virtual MatchResult MatchDevice(const DeviceCreateDesc& other,
- DeviceCreateDesc**) const;
-
- virtual bool UpdateMatchedCandidate(const DeviceCreateDesc&, bool* newDeviceFlag = NULL);
-
- virtual bool GetDeviceInfo(DeviceInfo* info) const;
-
- void SetScreenParameters(int x, int y, unsigned hres, unsigned vres, float hsize, float vsize)
- {
- DesktopX = x;
- DesktopY = y;
- HResolution = hres;
- VResolution = vres;
- HScreenSize = hsize;
- VScreenSize = vsize;
- Contents |= Contents_Screen;
- }
-
- void SetDistortion(const float* dks)
- {
- for (int i = 0; i < 4; i++)
- DistortionK[i] = dks[i];
- Contents |= Contents_Distortion;
- }
-
- void Set7Inch() { Contents |= Contents_7Inch; }
-
- bool Is7Inch() const;
-
-protected:
- String DeviceId;
- String DisplayDeviceName;
- int DesktopX, DesktopY;
- unsigned Contents;
- unsigned HResolution, VResolution;
- float HScreenSize, VScreenSize;
- long DisplayId;
- float DistortionK[4];
-};
-
-
-//-------------------------------------------------------------------------------------
-
-// HMDDevice represents an Oculus HMD device unit. An instance of this class
-// is typically created from the DeviceManager.
-// After HMD device is created, we its sensor data can be obtained by
-// first creating a Sensor object and then wrappig it in SensorFusion.
-
-class HMDDevice : public DeviceImpl<OVR::HMDDevice>
-{
-public:
- HMDDevice(HMDDeviceCreateDesc* createDesc);
- ~HMDDevice();
-
- virtual bool Initialize(DeviceBase* parent);
- virtual void Shutdown();
-
- // Query associated sensor.
- virtual OVR::SensorDevice* GetSensor();
-};
-
-
-}} // namespace OVR::OSX
-
-#endif // OVR_OSX_HMDDevice_h
-
+/************************************************************************************
+
+Filename : OVR_OSX_HMDDevice.h
+Content : OSX HMDDevice implementation
+Created : September 21, 2012
+Authors : Michael Antonov
+
+Copyright : Copyright 2012 Oculus VR, Inc. All Rights reserved.
+
+Use of this software is subject to the terms of the Oculus license
+agreement provided at the time of installation or download, or which
+otherwise accompanies this software in either electronic or hard copy form.
+
+*************************************************************************************/
+
+#ifndef OVR_OSX_HMDDevice_h
+#define OVR_OSX_HMDDevice_h
+
+#include "OVR_DeviceImpl.h"
+#include <Kernel/OVR_String.h>
+#include "OVR_Profile.h"
+
+namespace OVR { namespace OSX {
+
+class HMDDevice;
+
+
+//-------------------------------------------------------------------------------------
+
+// HMDDeviceFactory enumerates attached Oculus HMD devices.
+//
+// This is currently done by matching monitor device strings.
+
+class HMDDeviceFactory : public DeviceFactory
+{
+public:
+ static HMDDeviceFactory Instance;
+
+ // Enumerates devices, creating and destroying relevant objects in manager.
+ virtual void EnumerateDevices(EnumerateVisitor& visitor);
+
+protected:
+ DeviceManager* getManager() const { return (DeviceManager*) pManager; }
+};
+
+
+class HMDDeviceCreateDesc : public DeviceCreateDesc
+{
+ friend class HMDDevice;
+
+protected:
+ enum
+ {
+ Contents_Screen = 1,
+ Contents_Distortion = 2,
+ Contents_7Inch = 4,
+ };
+
+public:
+
+ HMDDeviceCreateDesc(DeviceFactory* factory,
+ UInt32 vendor, UInt32 product, const String& displayDeviceName, long dispId);
+ HMDDeviceCreateDesc(const HMDDeviceCreateDesc& other);
+
+ virtual DeviceCreateDesc* Clone() const
+ {
+ return new HMDDeviceCreateDesc(*this);
+ }
+
+ virtual DeviceBase* NewDeviceInstance();
+
+ virtual MatchResult MatchDevice(const DeviceCreateDesc& other,
+ DeviceCreateDesc**) const;
+
+ virtual bool UpdateMatchedCandidate(const DeviceCreateDesc&, bool* newDeviceFlag = NULL);
+
+ virtual bool GetDeviceInfo(DeviceInfo* info) const;
+
+ // Requests the currently used default profile. This profile affects the
+ // settings reported by HMDInfo.
+ Profile* GetProfileAddRef() const;
+
+ ProfileType GetProfileType() const
+ {
+ return (HResolution >= 1920) ? Profile_RiftDKHD : Profile_RiftDK1;
+ }
+
+ void SetScreenParameters(int x, int y, unsigned hres, unsigned vres, float hsize, float vsize)
+ {
+ DesktopX = x;
+ DesktopY = y;
+ HResolution = hres;
+ VResolution = vres;
+ HScreenSize = hsize;
+ VScreenSize = vsize;
+ Contents |= Contents_Screen;
+ }
+
+ void SetDistortion(const float* dks)
+ {
+ for (int i = 0; i < 4; i++)
+ DistortionK[i] = dks[i];
+ Contents |= Contents_Distortion;
+ }
+
+ void Set7Inch() { Contents |= Contents_7Inch; }
+
+ bool Is7Inch() const;
+
+protected:
+ String DeviceId;
+ String DisplayDeviceName;
+ int DesktopX, DesktopY;
+ unsigned Contents;
+ unsigned HResolution, VResolution;
+ float HScreenSize, VScreenSize;
+ long DisplayId;
+ float DistortionK[4];
+};
+
+
+//-------------------------------------------------------------------------------------
+
+// HMDDevice represents an Oculus HMD device unit. An instance of this class
+// is typically created from the DeviceManager.
+// After HMD device is created, we its sensor data can be obtained by
+// first creating a Sensor object and then wrappig it in SensorFusion.
+
+class HMDDevice : public DeviceImpl<OVR::HMDDevice>
+{
+public:
+ HMDDevice(HMDDeviceCreateDesc* createDesc);
+ ~HMDDevice();
+
+ virtual bool Initialize(DeviceBase* parent);
+ virtual void Shutdown();
+
+
+ // Requests the currently used default profile. This profile affects the
+ // settings reported by HMDInfo.
+ virtual Profile* GetProfile() const;
+ virtual const char* GetProfileName() const;
+ virtual bool SetProfileName(const char* name);
+
+ // Query associated sensor.
+ virtual OVR::SensorDevice* GetSensor();
+
+protected:
+ HMDDeviceCreateDesc* getDesc() const { return (HMDDeviceCreateDesc*)pCreateDesc.GetPtr(); }
+
+ // User name for the profile used with this device.
+ String ProfileName;
+ mutable Ptr<Profile> pCachedProfile;
+};
+
+
+}} // namespace OVR::OSX
+
+#endif // OVR_OSX_HMDDevice_h
+
diff --git a/LibOVR/Src/OVR_OSX_SensorDevice.cpp b/LibOVR/Src/OVR_OSX_SensorDevice.cpp
index da0726c..68e5e52 100644
--- a/LibOVR/Src/OVR_OSX_SensorDevice.cpp
+++ b/LibOVR/Src/OVR_OSX_SensorDevice.cpp
@@ -1,45 +1,45 @@
-/************************************************************************************
-
-Filename : OVR_OSX_SensorDevice.cpp
-Content : OSX SensorDevice implementation
-Created : March 14, 2013
-Authors : Lee Cooper
-
-Copyright : Copyright 2013 Oculus VR, Inc. All Rights reserved.
-
-Use of this software is subject to the terms of the Oculus license
-agreement provided at the time of installation or download, or which
-otherwise accompanies this software in either electronic or hard copy form.
-
-*************************************************************************************/
-
-#include "OVR_OSX_HMDDevice.h"
-#include "OVR_SensorImpl.h"
-#include "OVR_DeviceImpl.h"
-
-namespace OVR { namespace OSX {
-
-} // namespace OSX
-
-//-------------------------------------------------------------------------------------
-void SensorDeviceImpl::EnumerateHMDFromSensorDisplayInfo( const SensorDisplayInfoImpl& displayInfo,
- DeviceFactory::EnumerateVisitor& visitor)
-{
-
- OSX::HMDDeviceCreateDesc hmdCreateDesc(&OSX::HMDDeviceFactory::Instance, 1, 1, "", 0);
-
- hmdCreateDesc.SetScreenParameters( 0, 0,
- displayInfo.HResolution, displayInfo.VResolution,
- displayInfo.HScreenSize, displayInfo.VScreenSize);
-
- if ((displayInfo.DistortionType & SensorDisplayInfoImpl::Mask_BaseFmt) == SensorDisplayInfoImpl::Base_Distortion)
- hmdCreateDesc.SetDistortion(displayInfo.DistortionK);
- if (displayInfo.HScreenSize > 0.14f)
- hmdCreateDesc.Set7Inch();
-
- visitor.Visit(hmdCreateDesc);
-}
-
-} // namespace OVR
-
-
+/************************************************************************************
+
+Filename : OVR_OSX_SensorDevice.cpp
+Content : OSX SensorDevice implementation
+Created : March 14, 2013
+Authors : Lee Cooper
+
+Copyright : Copyright 2013 Oculus VR, Inc. All Rights reserved.
+
+Use of this software is subject to the terms of the Oculus license
+agreement provided at the time of installation or download, or which
+otherwise accompanies this software in either electronic or hard copy form.
+
+*************************************************************************************/
+
+#include "OVR_OSX_HMDDevice.h"
+#include "OVR_SensorImpl.h"
+#include "OVR_DeviceImpl.h"
+
+namespace OVR { namespace OSX {
+
+} // namespace OSX
+
+//-------------------------------------------------------------------------------------
+void SensorDeviceImpl::EnumerateHMDFromSensorDisplayInfo( const SensorDisplayInfoImpl& displayInfo,
+ DeviceFactory::EnumerateVisitor& visitor)
+{
+
+ OSX::HMDDeviceCreateDesc hmdCreateDesc(&OSX::HMDDeviceFactory::Instance, 1, 1, "", 0);
+
+ hmdCreateDesc.SetScreenParameters( 0, 0,
+ displayInfo.HResolution, displayInfo.VResolution,
+ displayInfo.HScreenSize, displayInfo.VScreenSize);
+
+ if ((displayInfo.DistortionType & SensorDisplayInfoImpl::Mask_BaseFmt) == SensorDisplayInfoImpl::Base_Distortion)
+ hmdCreateDesc.SetDistortion(displayInfo.DistortionK);
+ if (displayInfo.HScreenSize > 0.14f)
+ hmdCreateDesc.Set7Inch();
+
+ visitor.Visit(hmdCreateDesc);
+}
+
+} // namespace OVR
+
+
diff --git a/LibOVR/Src/OVR_Profile.cpp b/LibOVR/Src/OVR_Profile.cpp
new file mode 100644
index 0000000..7554a28
--- /dev/null
+++ b/LibOVR/Src/OVR_Profile.cpp
@@ -0,0 +1,664 @@
+/************************************************************************************
+
+PublicHeader: None
+Filename : OVR_Profile.cpp
+Content : Structs and functions for loading and storing device profile settings
+Created : February 14, 2013
+Notes :
+
+ Profiles are used to store per-user settings that can be transferred and used
+ across multiple applications. For example, player IPD can be configured once
+ and reused for a unified experience across games. Configuration and saving of profiles
+ can be accomplished in game via the Profile API or by the official Oculus Configuration
+ Utility.
+
+Copyright : Copyright 2013 Oculus VR, Inc. All Rights reserved.
+
+Use of this software is subject to the terms of the Oculus license
+agreement provided at the time of installation or download, or which
+otherwise accompanies this software in either electronic or hard copy form.
+
+************************************************************************************/
+
+#include "OVR_Profile.h"
+#include "OVR_JSON.h"
+#include "Kernel/OVR_Types.h"
+#include "Kernel/OVR_SysFile.h"
+#include "Kernel/OVR_Allocator.h"
+#include "Kernel/OVR_Array.h"
+
+#ifdef OVR_OS_WIN32
+#include <Shlobj.h>
+#else
+#include <dirent.h>
+#include <sys/stat.h>
+
+#ifdef OVR_OS_LINUX
+#include <unistd.h>
+#include <pwd.h>
+#endif
+
+#endif
+
+#define PROFILE_VERSION 1.0
+
+namespace OVR {
+
+//-----------------------------------------------------------------------------
+// Returns the pathname of the JSON file containing the stored profiles
+String GetProfilePath(bool create_dir)
+{
+ String path;
+
+#if defined(OVR_OS_WIN32)
+
+ PWSTR data_path = NULL;
+ SHGetKnownFolderPath(FOLDERID_LocalAppData, 0, NULL, &data_path);
+ path = String(data_path);
+ CoTaskMemFree(data_path);
+
+ path += "/Oculus";
+
+ if (create_dir)
+ { // Create the Oculus directory if it doesn't exist
+ WCHAR wpath[128];
+ OVR::UTF8Util::DecodeString(wpath, path.ToCStr());
+
+ DWORD attrib = GetFileAttributes(wpath);
+ bool exists = attrib != INVALID_FILE_ATTRIBUTES && (attrib & FILE_ATTRIBUTE_DIRECTORY);
+ if (!exists)
+ {
+ CreateDirectory(wpath, NULL);
+ }
+ }
+
+#elif defined(OVR_OS_MAC)
+
+ const char* home = getenv("HOME");
+ path = home;
+ path += "/Library/Preferences/Oculus";
+
+ if (create_dir)
+ { // Create the Oculus directory if it doesn't exist
+ DIR* dir = opendir(path);
+ if (dir == NULL)
+ {
+ mkdir(path, S_IRWXU | S_IRWXG | S_IRWXO);
+ }
+ else
+ {
+ closedir(dir);
+ }
+ }
+
+#else
+
+ passwd* pwd = getpwuid(getuid());
+ const char* home = pwd->pw_dir;
+ path = home;
+ path += "/.config/Oculus";
+
+ if (create_dir)
+ { // Create the Oculus directory if it doesn't exist
+ DIR* dir = opendir(path);
+ if (dir == NULL)
+ {
+ mkdir(path, S_IRWXU | S_IRWXG | S_IRWXO);
+ }
+ else
+ {
+ closedir(dir);
+ }
+ }
+
+#endif
+
+ path += "/Profiles.json";
+ return path;
+}
+
+
+//-----------------------------------------------------------------------------
+// ***** ProfileManager
+
+ProfileManager::ProfileManager()
+{
+ Changed = false;
+ CacheDevice = Profile_Unknown;
+}
+
+ProfileManager::~ProfileManager()
+{
+ // If the profiles have been altered then write out the profile file
+ if (Changed)
+ SaveCache();
+
+ ClearCache();
+}
+
+ProfileManager* ProfileManager::Create()
+{
+ return new ProfileManager();
+}
+
+Profile* ProfileManager::CreateProfileObject(const char* user,
+ ProfileType device,
+ const char** device_name)
+{
+ Lock::Locker lockScope(&ProfileLock);
+
+ Profile* profile = NULL;
+ switch (device)
+ {
+ case Profile_RiftDK1:
+ *device_name = "RiftDK1";
+ profile = new RiftDK1Profile(user);
+ break;
+ case Profile_RiftDKHD:
+ case Profile_Unknown:
+ break;
+ }
+
+ return profile;
+}
+
+
+// Clear the local profile cache
+void ProfileManager::ClearCache()
+{
+ Lock::Locker lockScope(&ProfileLock);
+
+ ProfileCache.Clear();
+ CacheDevice = Profile_Unknown;
+}
+
+
+// Poplulates the local profile cache. This occurs on the first access of the profile
+// data. All profile operations are performed against the local cache until the
+// ProfileManager is released or goes out of scope at which time the cache is serialized
+// to disk.
+void ProfileManager::LoadCache(ProfileType device)
+{
+ Lock::Locker lockScope(&ProfileLock);
+
+ ClearCache();
+
+ String path = GetProfilePath(false);
+
+ Ptr<JSON> root = *JSON::Load(path);
+ if (!root || root->GetItemCount() < 3)
+ return;
+
+ // First read the file type and version to make sure this is a valid file
+ JSON* item0 = root->GetFirstItem();
+ JSON* item1 = root->GetNextItem(item0);
+ JSON* item2 = root->GetNextItem(item1);
+
+ if (OVR_strcmp(item0->Name, "Oculus Profile Version") == 0)
+ { // In the future I may need to check versioning to determine parse method
+ }
+ else
+ {
+ return;
+ }
+
+ DefaultProfile = item1->Value;
+
+ // Read the number of profiles
+ int profileCount = (int)item2->dValue;
+ JSON* profileItem = item2;
+
+ for (int p=0; p<profileCount; p++)
+ {
+ profileItem = profileItem->GetNextItem(profileItem);
+ if (!profileItem)
+ break;
+
+ // Read the required Name field
+ const char* profileName;
+ JSON* item = profileItem->GetFirstItem();
+
+ if (item && (OVR_strcmp(item->Name, "Name") == 0))
+ {
+ profileName = item->Value;
+ }
+ else
+ {
+ return; // invalid field
+ }
+
+ const char* deviceName = 0;
+ bool deviceFound = false;
+ Ptr<Profile> profile = *CreateProfileObject(profileName, device, &deviceName);
+
+ // Read the base profile fields.
+ while (item = profileItem->GetNextItem(item), item)
+ {
+ if (item->Type != JSON_Object)
+ {
+ 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)
+ {
+ deviceFound = true;
+
+ for (JSON* deviceItem = item->GetFirstItem(); deviceItem;
+ deviceItem = item->GetNextItem(deviceItem))
+ {
+ profile->ParseProperty(deviceItem->Name, deviceItem->Value);
+ }
+ }
+ }
+ }
+
+ // Add the new profile
+ if (deviceFound)
+ ProfileCache.PushBack(profile);
+ }
+
+ CacheDevice = device;
+}
+
+
+// Serializes the profiles to disk.
+void ProfileManager::SaveCache()
+{
+ String path = GetProfilePath(true);
+
+ Lock::Locker lockScope(&ProfileLock);
+
+ // TODO: Since there is only a single device type now, a full tree overwrite
+ // is sufficient but in the future a selective device branch replacement will
+ // be necessary
+
+ Ptr<JSON> root = *JSON::CreateObject();
+ root->AddNumberItem("Oculus Profile Version", PROFILE_VERSION);
+ root->AddStringItem("CurrentProfile", DefaultProfile);
+ root->AddNumberItem("ProfileCount", (double) ProfileCache.GetSize());
+
+ // Generate a JSON subtree for each profile
+ for (unsigned int i=0; i<ProfileCache.GetSize(); i++)
+ {
+ Profile* profile = ProfileCache[i];
+
+ JSON* json_profile = JSON::CreateObject();
+ json_profile->Name = "Profile";
+ json_profile->AddStringItem("Name", profile->Name);
+ const char* gender;
+ switch (profile->GetGender())
+ {
+ case Profile::Gender_Male: gender = "Male"; break;
+ case Profile::Gender_Female: gender = "Female"; break;
+ default: gender = "Unspecified";
+ }
+ json_profile->AddStringItem("Gender", gender);
+ json_profile->AddNumberItem("PlayerHeight", profile->PlayerHeight);
+ json_profile->AddNumberItem("IPD", profile->IPD);
+
+ if (profile->Type == Profile_RiftDK1)
+ {
+ RiftDK1Profile* riftdk1 = (RiftDK1Profile*)profile;
+ JSON* json_riftdk1 = JSON::CreateObject();
+ json_profile->AddItem("RiftDK1", json_riftdk1);
+
+ const char* eyecup = "A";
+ switch (riftdk1->EyeCups)
+ {
+ case RiftDK1Profile::EyeCup_A: eyecup = "A"; break;
+ case RiftDK1Profile::EyeCup_B: eyecup = "B"; break;
+ case RiftDK1Profile::EyeCup_C: eyecup = "C"; break;
+ }
+ json_riftdk1->AddStringItem("EyeCup", eyecup);
+ json_riftdk1->AddNumberItem("LL", riftdk1->LL);
+ json_riftdk1->AddNumberItem("LR", riftdk1->LR);
+ json_riftdk1->AddNumberItem("RL", riftdk1->RL);
+ json_riftdk1->AddNumberItem("RR", riftdk1->RR);
+ }
+
+ root->AddItem("Profile", json_profile);
+ }
+
+ root->Save(path);
+}
+
+// Returns the number of stored profiles for this device type
+int ProfileManager::GetProfileCount(ProfileType device)
+{
+ Lock::Locker lockScope(&ProfileLock);
+
+ if (CacheDevice == Profile_Unknown)
+ LoadCache(device);
+
+ return (int)ProfileCache.GetSize();
+}
+
+// Returns the profile name of a specific profile in the list. The returned
+// memory is locally allocated and should not be stored or deleted. Returns NULL
+// if the index is invalid
+const char* ProfileManager::GetProfileName(ProfileType device, unsigned int index)
+{
+ Lock::Locker lockScope(&ProfileLock);
+
+ if (CacheDevice == Profile_Unknown)
+ LoadCache(device);
+
+ if (index < ProfileCache.GetSize())
+ {
+ Profile* profile = ProfileCache[index];
+ OVR_strcpy(NameBuff, Profile::MaxNameLen, profile->Name);
+ return NameBuff;
+ }
+ else
+ {
+ return NULL;
+ }
+}
+
+bool ProfileManager::HasProfile(ProfileType device, const char* name)
+{
+ Lock::Locker lockScope(&ProfileLock);
+
+ if (CacheDevice == Profile_Unknown)
+ LoadCache(device);
+
+ for (unsigned i = 0; i< ProfileCache.GetSize(); i++)
+ {
+ if (ProfileCache[i] && OVR_strcmp(ProfileCache[i]->Name, name) == 0)
+ return true;
+ }
+ return false;
+}
+
+
+// Returns a specific profile object in the list. The returned memory should be
+// encapsulated in a Ptr<> object or released after use. Returns NULL if the index
+// is invalid
+Profile* ProfileManager::LoadProfile(ProfileType device, unsigned int index)
+{
+ Lock::Locker lockScope(&ProfileLock);
+
+ if (CacheDevice == Profile_Unknown)
+ LoadCache(device);
+
+ if (index < ProfileCache.GetSize())
+ {
+ Profile* profile = ProfileCache[index];
+ return profile->Clone();
+ }
+ else
+ {
+ return NULL;
+ }
+}
+
+// Returns a profile object for a particular device and user name. The returned
+// memory should be encapsulated in a Ptr<> object or released after use. Returns
+// NULL if the profile is not found
+Profile* ProfileManager::LoadProfile(ProfileType device, const char* user)
+{
+ if (user == NULL)
+ return NULL;
+
+ Lock::Locker lockScope(&ProfileLock);
+
+ if (CacheDevice == Profile_Unknown)
+ LoadCache(device);
+
+ for (unsigned int i=0; i<ProfileCache.GetSize(); i++)
+ {
+ if (OVR_strcmp(user, ProfileCache[i]->Name) == 0)
+ { // Found the requested user profile
+ Profile* profile = ProfileCache[i];
+ return profile->Clone();
+ }
+ }
+
+ return NULL;
+}
+
+// Returns a profile with all system default values
+Profile* ProfileManager::GetDeviceDefaultProfile(ProfileType device)
+{
+ const char* device_name = NULL;
+ return CreateProfileObject("default", device, &device_name);
+}
+
+// Returns the name of the profile that is marked as the current default user.
+const char* ProfileManager::GetDefaultProfileName(ProfileType device)
+{
+ Lock::Locker lockScope(&ProfileLock);
+
+ if (CacheDevice == Profile_Unknown)
+ LoadCache(device);
+
+ if (ProfileCache.GetSize() > 0)
+ {
+ OVR_strcpy(NameBuff, Profile::MaxNameLen, DefaultProfile);
+ return NameBuff;
+ }
+ else
+ {
+ return NULL;
+ }
+}
+
+// Marks a particular user as the current default user.
+bool ProfileManager::SetDefaultProfileName(ProfileType device, const char* name)
+{
+ Lock::Locker lockScope(&ProfileLock);
+
+ if (CacheDevice == Profile_Unknown)
+ LoadCache(device);
+// TODO: I should verify that the user is valid
+ if (ProfileCache.GetSize() > 0)
+ {
+ DefaultProfile = name;
+ Changed = true;
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+}
+
+
+// Saves a new or existing profile. Returns true on success or false on an
+// invalid or failed save.
+bool ProfileManager::Save(const Profile* profile)
+{
+ Lock::Locker lockScope(&ProfileLock);
+
+ if (OVR_strcmp(profile->Name, "default") == 0)
+ return false; // don't save a default profile
+
+ // TODO: I should also verify that this profile type matches the current cache
+ if (CacheDevice == Profile_Unknown)
+ LoadCache(profile->Type);
+
+ // Look for the pre-existence of this profile
+ bool added = false;
+ for (unsigned int i=0; i<ProfileCache.GetSize(); i++)
+ {
+ int compare = OVR_strcmp(profile->Name, ProfileCache[i]->Name);
+
+ if (compare == 0)
+ {
+ // TODO: I should do a proper field comparison to avoid unnecessary
+ // overwrites and file saves
+
+ // Replace the previous instance with the new profile
+ ProfileCache[i] = *profile->Clone();
+ added = true;
+ Changed = true;
+ break;
+ }
+ }
+
+ if (!added)
+ {
+ ProfileCache.PushBack(*profile->Clone());
+ if (ProfileCache.GetSize() == 1)
+ CacheDevice = profile->Type;
+
+ Changed = true;
+ }
+
+ return true;
+}
+
+// Removes an existing profile. Returns true if the profile was found and deleted
+// and returns false otherwise.
+bool ProfileManager::Delete(const Profile* profile)
+{
+ Lock::Locker lockScope(&ProfileLock);
+
+ if (OVR_strcmp(profile->Name, "default") == 0)
+ return false; // don't delete a default profile
+
+ if (CacheDevice == Profile_Unknown)
+ LoadCache(profile->Type);
+
+ // Look for the existence of this profile
+ for (unsigned int i=0; i<ProfileCache.GetSize(); i++)
+ {
+ if (OVR_strcmp(profile->Name, ProfileCache[i]->Name) == 0)
+ {
+ if (OVR_strcmp(profile->Name, DefaultProfile) == 0)
+ DefaultProfile.Clear();
+
+ ProfileCache.RemoveAt(i);
+ Changed = true;
+ return true;
+ }
+ }
+
+ return false;
+}
+
+
+
+//-----------------------------------------------------------------------------
+// ***** Profile
+
+Profile::Profile(ProfileType device, const char* name)
+{
+ Type = device;
+ Gender = Gender_Unspecified;
+ PlayerHeight = 1.778f; // 5'10" inch man
+ IPD = 0.064f;
+ OVR_strcpy(Name, MaxNameLen, name);
+}
+
+
+bool Profile::ParseProperty(const char* prop, const char* sval)
+{
+ if (OVR_strcmp(prop, "Name") == 0)
+ {
+ OVR_strcpy(Name, MaxNameLen, sval);
+ return true;
+ }
+ else if (OVR_strcmp(prop, "Gender") == 0)
+ {
+ if (OVR_strcmp(sval, "Male") == 0)
+ Gender = Gender_Male;
+ else if (OVR_strcmp(sval, "Female") == 0)
+ Gender = Gender_Female;
+ else
+ Gender = Gender_Unspecified;
+
+ return true;
+ }
+ else if (OVR_strcmp(prop, "PlayerHeight") == 0)
+ {
+ PlayerHeight = (float)atof(sval);
+ return true;
+ }
+ else if (OVR_strcmp(prop, "IPD") == 0)
+ {
+ IPD = (float)atof(sval);
+ return true;
+ }
+
+ return false;
+}
+
+
+// Computes the eye height from the metric head height
+float Profile::GetEyeHeight()
+{
+ const float EYE_TO_HEADTOP_RATIO = 0.44538f;
+ const float MALE_AVG_HEAD_HEIGHT = 0.232f;
+ const float FEMALE_AVG_HEAD_HEIGHT = 0.218f;
+
+ // compute distance from top of skull to the eye
+ float head_height;
+ if (Gender == Gender_Female)
+ head_height = FEMALE_AVG_HEAD_HEIGHT;
+ else
+ head_height = MALE_AVG_HEAD_HEIGHT;
+
+ float skull = EYE_TO_HEADTOP_RATIO * head_height;
+
+ float eye_height = PlayerHeight - skull;
+ return eye_height;
+}
+
+
+//-----------------------------------------------------------------------------
+// ***** RiftDK1Profile
+
+RiftDK1Profile::RiftDK1Profile(const char* name) : Profile(Profile_RiftDK1, name)
+{
+ EyeCups = EyeCup_A;
+ LL = 0;
+ LR = 0;
+ RL = 0;
+ RR = 0;
+}
+
+bool RiftDK1Profile::ParseProperty(const char* prop, const char* sval)
+{
+ if (OVR_strcmp(prop, "EyeCup") == 0)
+ {
+ switch (sval[0])
+ {
+ case 'C': EyeCups = EyeCup_C; break;
+ case 'B': EyeCups = EyeCup_B; break;
+ default: EyeCups = EyeCup_A; break;
+ }
+ return true;
+ }
+ else if (OVR_strcmp(prop, "LL") == 0)
+ {
+ LL = atoi(sval);
+ return true;
+ }
+ else if (OVR_strcmp(prop, "LR") == 0)
+ {
+ LR = atoi(sval);
+ return true;
+ }
+ else if (OVR_strcmp(prop, "RL") == 0)
+ {
+ RL = atoi(sval);
+ return true;
+ }
+ else if (OVR_strcmp(prop, "RR") == 0)
+ {
+ RR = atoi(sval);
+ return true;
+ }
+
+ return Profile::ParseProperty(prop, sval);
+}
+
+Profile* RiftDK1Profile::Clone() const
+{
+ RiftDK1Profile* profile = new RiftDK1Profile(*this);
+ return profile;
+}
+
+} // OVR
diff --git a/LibOVR/Src/OVR_Profile.h b/LibOVR/Src/OVR_Profile.h
new file mode 100644
index 0000000..bfd8ea9
--- /dev/null
+++ b/LibOVR/Src/OVR_Profile.h
@@ -0,0 +1,186 @@
+/************************************************************************************
+
+PublicHeader: OVR.h
+Filename : OVR_Profile.h
+Content : Structs and functions for loading and storing device profile settings
+Created : February 14, 2013
+Notes :
+ Profiles are used to store per-user settings that can be transferred and used
+ across multiple applications. For example, player IPD can be configured once
+ and reused for a unified experience across games. Configuration and saving of profiles
+ can be accomplished in game via the Profile API or by the official Oculus Configuration
+ Utility.
+
+Copyright : Copyright 2013 Oculus VR, Inc. All Rights reserved.
+
+Use of this software is subject to the terms of the Oculus license
+agreement provided at the time of installation or download, or which
+otherwise accompanies this software in either electronic or hard copy form.
+
+************************************************************************************/
+
+#ifndef OVR_Profile_h
+#define OVR_Profile_h
+
+#include "Kernel/OVR_String.h"
+#include "Kernel/OVR_RefCount.h"
+#include "Kernel/OVR_Array.h"
+
+namespace OVR {
+
+// Defines the profile object for each device type
+enum ProfileType
+{
+ Profile_Unknown = 0,
+ Profile_RiftDK1 = 1,
+ Profile_RiftDKHD = 2,
+};
+
+class Profile;
+
+// -----------------------------------------------------------------------------
+// ***** ProfileManager
+
+// Profiles are interfaced through a ProfileManager object. Applications should
+// create a ProfileManager each time they intend to read or write user profile data.
+// The scope of the ProfileManager object defines when disk I/O is performed. Disk
+// reads are performed on the first profile access and disk writes are performed when
+// the ProfileManager goes out of scope. All profile interactions between these times
+// are performed in local memory and are fast. A typical profile interaction might
+// look like this:
+//
+// {
+// Ptr<ProfileManager> pm = *ProfileManager::Create();
+// Ptr<Profile> profile = pm->LoadProfile(Profile_RiftDK1,
+// pm->GetDefaultProfileName(Profile_RiftDK1));
+// if (profile)
+// { // Retrieve the current profile settings
+// }
+// } // Profile will be destroyed and any disk I/O completed when going out of scope
+
+class ProfileManager : public RefCountBase<ProfileManager>
+{
+protected:
+ // Synchronize ProfileManager access since it may be accessed from multiple threads,
+ // as it's shared through DeviceManager.
+ Lock ProfileLock;
+ Array<Ptr<Profile> > ProfileCache;
+ ProfileType CacheDevice;
+ String DefaultProfile;
+ bool Changed;
+ char NameBuff[32];
+
+public:
+ static ProfileManager* Create();
+
+ // Static interface functions
+ int GetProfileCount(ProfileType device);
+ const char* GetProfileName(ProfileType device, unsigned int index);
+ bool HasProfile(ProfileType device, const char* name);
+ Profile* LoadProfile(ProfileType device, unsigned int index);
+ Profile* LoadProfile(ProfileType device, const char* name);
+ Profile* GetDeviceDefaultProfile(ProfileType device);
+ const char* GetDefaultProfileName(ProfileType device);
+ bool SetDefaultProfileName(ProfileType device, const char* name);
+ bool Save(const Profile* profile);
+ bool Delete(const Profile* profile);
+
+protected:
+ ProfileManager();
+ ~ProfileManager();
+ void LoadCache(ProfileType device);
+ void SaveCache();
+ void ClearCache();
+ Profile* CreateProfileObject(const char* user,
+ ProfileType device,
+ const char** device_name);
+};
+
+//-------------------------------------------------------------------
+// ***** Profile
+
+// The base profile for all HMD devices. This object is never created directly.
+// Instead derived objects provide specific data implementations. Some settings
+// such as IPD will be tied to a specific user and be consistent between ,
+// implementations but other settings like optical distortion may vary between devices.
+
+class Profile : public RefCountBase<Profile>
+{
+public:
+ enum { MaxNameLen = 32 };
+
+ enum GenderType
+ {
+ Gender_Unspecified = 0,
+ Gender_Male = 1,
+ Gender_Female = 2
+ };
+
+ ProfileType Type; // The type of device profile
+ char Name[MaxNameLen]; // The name given to this profile
+
+protected:
+ GenderType Gender; // The gender of the user
+ float PlayerHeight; // The height of the user in meters
+ float IPD; // Distance between eyes in meters
+
+public:
+ // These are properties which are intrinsic to the user and affect scene setup
+ GenderType GetGender() { return Gender; };
+ float GetPlayerHeight() { return PlayerHeight; };
+ float GetIPD() { return IPD; };
+ float GetEyeHeight();
+
+ void SetGender(GenderType gender) { Gender = gender; };
+ void SetPlayerHeight(float height) { PlayerHeight = height; };
+ void SetIPD(float ipd) { IPD = ipd; };
+
+
+protected:
+ Profile(ProfileType type, const char* name);
+
+ virtual Profile* Clone() const = 0;
+ virtual bool ParseProperty(const char* prop, const char* sval);
+
+ friend class ProfileManager;
+};
+
+
+//-----------------------------------------------------------------------------
+// ***** RiftDK1Profile
+
+// This profile is specific to the Rift Dev Kit 1 and contains overrides specific
+// to that device and lens cup settings.
+class RiftDK1Profile : public Profile
+{
+public:
+ enum EyeCupType
+ {
+ EyeCup_A = 0,
+ EyeCup_B = 1,
+ EyeCup_C = 2
+ };
+
+protected:
+ EyeCupType EyeCups; // Which eye cup does the player use
+ int LL; // Configuration Utility IPD setting
+ int LR; // Configuration Utility IPD setting
+ int RL; // Configuration Utility IPD setting
+ int RR; // Configuration Utility IPD setting
+
+public:
+ EyeCupType GetEyeCup() { return EyeCups; };
+ void SetEyeCup(EyeCupType cup) { EyeCups = cup; };
+
+protected:
+ RiftDK1Profile(const char* name);
+
+ virtual Profile* Clone() const;
+ virtual bool ParseProperty(const char* prop, const char* sval);
+
+ friend class ProfileManager;
+};
+
+}
+
+#endif // OVR_Profile_h \ No newline at end of file
diff --git a/LibOVR/Src/OVR_SensorFilter.cpp b/LibOVR/Src/OVR_SensorFilter.cpp
index 6bd71b5..75c3b5b 100644
--- a/LibOVR/Src/OVR_SensorFilter.cpp
+++ b/LibOVR/Src/OVR_SensorFilter.cpp
@@ -1,201 +1,201 @@
-/************************************************************************************
-
-PublicHeader: OVR.h
-Filename : OVR_SensorFilter.cpp
-Content : Basic filtering of sensor data
-Created : March 7, 2013
-Authors : Steve LaValle, Anna Yershova
-
-Copyright : Copyright 2012 Oculus VR, Inc. All Rights reserved.
-
-Use of this software is subject to the terms of the Oculus license
-agreement provided at the time of installation or download, or which
-otherwise accompanies this software in either electronic or hard copy form.
-
-*************************************************************************************/
-
-#include "OVR_SensorFilter.h"
-
-namespace OVR {
-
-Vector3f SensorFilter::Total() const
-{
- Vector3f total = Vector3f(0.0f, 0.0f, 0.0f);
- for (int i = 0; i < Size; i++)
- total += Elements[i];
- return total;
-}
-
-Vector3f SensorFilter::Mean() const
-{
- Vector3f total = Vector3f(0.0f, 0.0f, 0.0f);
- for (int i = 0; i < Size; i++)
- total += Elements[i];
- return total / (float) Size;
-}
-
-Vector3f SensorFilter::Median() const
-{
- int half_window = (int) Size / 2;
- float sortx[MaxFilterSize];
- float resultx = 0.0f;
-
- float sorty[MaxFilterSize];
- float resulty = 0.0f;
-
- float sortz[MaxFilterSize];
- float resultz = 0.0f;
-
- for (int i = 0; i < Size; i++)
- {
- sortx[i] = Elements[i].x;
- sorty[i] = Elements[i].y;
- sortz[i] = Elements[i].z;
- }
- for (int j = 0; j <= half_window; j++)
- {
- int minx = j;
- int miny = j;
- int minz = j;
- for (int k = j + 1; k < Size; k++)
- {
- if (sortx[k] < sortx[minx]) minx = k;
- if (sorty[k] < sorty[miny]) miny = k;
- if (sortz[k] < sortz[minz]) minz = k;
- }
- const float tempx = sortx[j];
- const float tempy = sorty[j];
- const float tempz = sortz[j];
- sortx[j] = sortx[minx];
- sortx[minx] = tempx;
-
- sorty[j] = sorty[miny];
- sorty[miny] = tempy;
-
- sortz[j] = sortz[minz];
- sortz[minz] = tempz;
- }
- resultx = sortx[half_window];
- resulty = sorty[half_window];
- resultz = sortz[half_window];
-
- return Vector3f(resultx, resulty, resultz);
-}
-
-// Only the diagonal of the covariance matrix.
-Vector3f SensorFilter::Variance() const
-{
- Vector3f mean = Mean();
- Vector3f total = Vector3f(0.0f, 0.0f, 0.0f);
- for (int i = 0; i < Size; i++)
- {
- total.x += (Elements[i].x - mean.x) * (Elements[i].x - mean.x);
- total.y += (Elements[i].y - mean.y) * (Elements[i].y - mean.y);
- total.z += (Elements[i].z - mean.z) * (Elements[i].z - mean.z);
- }
- return total / (float) Size;
-}
-
-// Should be a 3x3 matrix returned, but OVR_math.h doesn't have one
-Matrix4f SensorFilter::Covariance() const
-{
- Vector3f mean = Mean();
- Matrix4f total = Matrix4f(0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0);
- for (int i = 0; i < Size; i++)
- {
- total.M[0][0] += (Elements[i].x - mean.x) * (Elements[i].x - mean.x);
- total.M[1][0] += (Elements[i].y - mean.y) * (Elements[i].x - mean.x);
- total.M[2][0] += (Elements[i].z - mean.z) * (Elements[i].x - mean.x);
- total.M[1][1] += (Elements[i].y - mean.y) * (Elements[i].y - mean.y);
- total.M[2][1] += (Elements[i].z - mean.z) * (Elements[i].y - mean.y);
- total.M[2][2] += (Elements[i].z - mean.z) * (Elements[i].z - mean.z);
- }
- total.M[0][1] = total.M[1][0];
- total.M[0][2] = total.M[2][0];
- total.M[1][2] = total.M[2][1];
- for (int i = 0; i < 3; i++)
- for (int j = 0; j < 3; j++)
- total.M[i][j] *= 1.0f / Size;
- return total;
-}
-
-Vector3f SensorFilter::PearsonCoefficient() const
-{
- Matrix4f cov = Covariance();
- Vector3f pearson = Vector3f();
- pearson.x = cov.M[0][1]/(sqrt(cov.M[0][0])*sqrt(cov.M[1][1]));
- pearson.y = cov.M[1][2]/(sqrt(cov.M[1][1])*sqrt(cov.M[2][2]));
- pearson.z = cov.M[2][0]/(sqrt(cov.M[2][2])*sqrt(cov.M[0][0]));
-
- return pearson;
-}
-
-
-Vector3f SensorFilter::SavitzkyGolaySmooth8() const
-{
- OVR_ASSERT(Size >= 8);
- return GetPrev(0)*0.41667f +
- GetPrev(1)*0.33333f +
- GetPrev(2)*0.25f +
- GetPrev(3)*0.16667f +
- GetPrev(4)*0.08333f -
- GetPrev(6)*0.08333f -
- GetPrev(7)*0.16667f;
-}
-
-
-Vector3f SensorFilter::SavitzkyGolayDerivative4() const
-{
- OVR_ASSERT(Size >= 4);
- return GetPrev(0)*0.3f +
- GetPrev(1)*0.1f -
- GetPrev(2)*0.1f -
- GetPrev(3)*0.3f;
-}
-
-Vector3f SensorFilter::SavitzkyGolayDerivative5() const
-{
- OVR_ASSERT(Size >= 5);
- return GetPrev(0)*0.2f +
- GetPrev(1)*0.1f -
- GetPrev(3)*0.1f -
- GetPrev(4)*0.2f;
-}
-
-Vector3f SensorFilter::SavitzkyGolayDerivative12() const
-{
- OVR_ASSERT(Size >= 12);
- return GetPrev(0)*0.03846f +
- GetPrev(1)*0.03147f +
- GetPrev(2)*0.02448f +
- GetPrev(3)*0.01748f +
- GetPrev(4)*0.01049f +
- GetPrev(5)*0.0035f -
- GetPrev(6)*0.0035f -
- GetPrev(7)*0.01049f -
- GetPrev(8)*0.01748f -
- GetPrev(9)*0.02448f -
- GetPrev(10)*0.03147f -
- GetPrev(11)*0.03846f;
-}
-
-Vector3f SensorFilter::SavitzkyGolayDerivativeN(int n) const
-{
- OVR_ASSERT(Size >= n);
- int m = (n-1)/2;
- Vector3f result = Vector3f();
- for (int k = 1; k <= m; k++)
- {
- int ind1 = m - k;
- int ind2 = n - m + k - 1;
- result += (GetPrev(ind1) - GetPrev(ind2)) * (float) k;
- }
- float coef = 3.0f/(m*(m+1.0f)*(2.0f*m+1.0f));
- result = result*coef;
- return result;
-}
-
-
-
-
+/************************************************************************************
+
+PublicHeader: OVR.h
+Filename : OVR_SensorFilter.cpp
+Content : Basic filtering of sensor data
+Created : March 7, 2013
+Authors : Steve LaValle, Anna Yershova
+
+Copyright : Copyright 2012 Oculus VR, Inc. All Rights reserved.
+
+Use of this software is subject to the terms of the Oculus license
+agreement provided at the time of installation or download, or which
+otherwise accompanies this software in either electronic or hard copy form.
+
+*************************************************************************************/
+
+#include "OVR_SensorFilter.h"
+
+namespace OVR {
+
+Vector3f SensorFilter::Total() const
+{
+ Vector3f total = Vector3f(0.0f, 0.0f, 0.0f);
+ for (int i = 0; i < Size; i++)
+ total += Elements[i];
+ return total;
+}
+
+Vector3f SensorFilter::Mean() const
+{
+ Vector3f total = Vector3f(0.0f, 0.0f, 0.0f);
+ for (int i = 0; i < Size; i++)
+ total += Elements[i];
+ return total / (float) Size;
+}
+
+Vector3f SensorFilter::Median() const
+{
+ int half_window = (int) Size / 2;
+ float sortx[MaxFilterSize];
+ float resultx = 0.0f;
+
+ float sorty[MaxFilterSize];
+ float resulty = 0.0f;
+
+ float sortz[MaxFilterSize];
+ float resultz = 0.0f;
+
+ for (int i = 0; i < Size; i++)
+ {
+ sortx[i] = Elements[i].x;
+ sorty[i] = Elements[i].y;
+ sortz[i] = Elements[i].z;
+ }
+ for (int j = 0; j <= half_window; j++)
+ {
+ int minx = j;
+ int miny = j;
+ int minz = j;
+ for (int k = j + 1; k < Size; k++)
+ {
+ if (sortx[k] < sortx[minx]) minx = k;
+ if (sorty[k] < sorty[miny]) miny = k;
+ if (sortz[k] < sortz[minz]) minz = k;
+ }
+ const float tempx = sortx[j];
+ const float tempy = sorty[j];
+ const float tempz = sortz[j];
+ sortx[j] = sortx[minx];
+ sortx[minx] = tempx;
+
+ sorty[j] = sorty[miny];
+ sorty[miny] = tempy;
+
+ sortz[j] = sortz[minz];
+ sortz[minz] = tempz;
+ }
+ resultx = sortx[half_window];
+ resulty = sorty[half_window];
+ resultz = sortz[half_window];
+
+ return Vector3f(resultx, resulty, resultz);
+}
+
+// Only the diagonal of the covariance matrix.
+Vector3f SensorFilter::Variance() const
+{
+ Vector3f mean = Mean();
+ Vector3f total = Vector3f(0.0f, 0.0f, 0.0f);
+ for (int i = 0; i < Size; i++)
+ {
+ total.x += (Elements[i].x - mean.x) * (Elements[i].x - mean.x);
+ total.y += (Elements[i].y - mean.y) * (Elements[i].y - mean.y);
+ total.z += (Elements[i].z - mean.z) * (Elements[i].z - mean.z);
+ }
+ return total / (float) Size;
+}
+
+// Should be a 3x3 matrix returned, but OVR_math.h doesn't have one
+Matrix4f SensorFilter::Covariance() const
+{
+ Vector3f mean = Mean();
+ Matrix4f total = Matrix4f(0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0);
+ for (int i = 0; i < Size; i++)
+ {
+ total.M[0][0] += (Elements[i].x - mean.x) * (Elements[i].x - mean.x);
+ total.M[1][0] += (Elements[i].y - mean.y) * (Elements[i].x - mean.x);
+ total.M[2][0] += (Elements[i].z - mean.z) * (Elements[i].x - mean.x);
+ total.M[1][1] += (Elements[i].y - mean.y) * (Elements[i].y - mean.y);
+ total.M[2][1] += (Elements[i].z - mean.z) * (Elements[i].y - mean.y);
+ total.M[2][2] += (Elements[i].z - mean.z) * (Elements[i].z - mean.z);
+ }
+ total.M[0][1] = total.M[1][0];
+ total.M[0][2] = total.M[2][0];
+ total.M[1][2] = total.M[2][1];
+ for (int i = 0; i < 3; i++)
+ for (int j = 0; j < 3; j++)
+ total.M[i][j] *= 1.0f / Size;
+ return total;
+}
+
+Vector3f SensorFilter::PearsonCoefficient() const
+{
+ Matrix4f cov = Covariance();
+ Vector3f pearson = Vector3f();
+ pearson.x = cov.M[0][1]/(sqrt(cov.M[0][0])*sqrt(cov.M[1][1]));
+ pearson.y = cov.M[1][2]/(sqrt(cov.M[1][1])*sqrt(cov.M[2][2]));
+ pearson.z = cov.M[2][0]/(sqrt(cov.M[2][2])*sqrt(cov.M[0][0]));
+
+ return pearson;
+}
+
+
+Vector3f SensorFilter::SavitzkyGolaySmooth8() const
+{
+ OVR_ASSERT(Size >= 8);
+ return GetPrev(0)*0.41667f +
+ GetPrev(1)*0.33333f +
+ GetPrev(2)*0.25f +
+ GetPrev(3)*0.16667f +
+ GetPrev(4)*0.08333f -
+ GetPrev(6)*0.08333f -
+ GetPrev(7)*0.16667f;
+}
+
+
+Vector3f SensorFilter::SavitzkyGolayDerivative4() const
+{
+ OVR_ASSERT(Size >= 4);
+ return GetPrev(0)*0.3f +
+ GetPrev(1)*0.1f -
+ GetPrev(2)*0.1f -
+ GetPrev(3)*0.3f;
+}
+
+Vector3f SensorFilter::SavitzkyGolayDerivative5() const
+{
+ OVR_ASSERT(Size >= 5);
+ return GetPrev(0)*0.2f +
+ GetPrev(1)*0.1f -
+ GetPrev(3)*0.1f -
+ GetPrev(4)*0.2f;
+}
+
+Vector3f SensorFilter::SavitzkyGolayDerivative12() const
+{
+ OVR_ASSERT(Size >= 12);
+ return GetPrev(0)*0.03846f +
+ GetPrev(1)*0.03147f +
+ GetPrev(2)*0.02448f +
+ GetPrev(3)*0.01748f +
+ GetPrev(4)*0.01049f +
+ GetPrev(5)*0.0035f -
+ GetPrev(6)*0.0035f -
+ GetPrev(7)*0.01049f -
+ GetPrev(8)*0.01748f -
+ GetPrev(9)*0.02448f -
+ GetPrev(10)*0.03147f -
+ GetPrev(11)*0.03846f;
+}
+
+Vector3f SensorFilter::SavitzkyGolayDerivativeN(int n) const
+{
+ OVR_ASSERT(Size >= n);
+ int m = (n-1)/2;
+ Vector3f result = Vector3f();
+ for (int k = 1; k <= m; k++)
+ {
+ int ind1 = m - k;
+ int ind2 = n - m + k - 1;
+ result += (GetPrev(ind1) - GetPrev(ind2)) * (float) k;
+ }
+ float coef = 3.0f/(m*(m+1.0f)*(2.0f*m+1.0f));
+ result = result*coef;
+ return result;
+}
+
+
+
+
} //namespace OVR \ No newline at end of file
diff --git a/LibOVR/Src/OVR_SensorFilter.h b/LibOVR/Src/OVR_SensorFilter.h
index 18665b1..857e719 100644
--- a/LibOVR/Src/OVR_SensorFilter.h
+++ b/LibOVR/Src/OVR_SensorFilter.h
@@ -1,99 +1,99 @@
-/************************************************************************************
-
-PublicHeader: OVR.h
-Filename : OVR_SensorFilter.h
-Content : Basic filtering of sensor data
-Created : March 7, 2013
-Authors : Steve LaValle, Anna Yershova
-
-Copyright : Copyright 2012 Oculus VR, Inc. All Rights reserved.
-
-Use of this software is subject to the terms of the Oculus license
-agreement provided at the time of installation or download, or which
-otherwise accompanies this software in either electronic or hard copy form.
-
-*************************************************************************************/
-
-#ifndef OVR_SensorFilter_h
-#define OVR_SensorFilter_h
-
-#include "Kernel/OVR_Math.h"
-
-
-namespace OVR {
-
-// This class maintains a sliding window of sensor data taken over time and implements
-// various simple filters, most of which are linear functions of the data history.
-class SensorFilter
-{
- enum
- {
- MaxFilterSize = 100,
- DefaultFilterSize = 20
- };
-
-private:
- int LastIdx; // The index of the last element that was added to the array
- int Size; // The window size (number of elements)
- Vector3f Elements[MaxFilterSize];
-
-public:
- // Create a new filter with default size
- SensorFilter()
- {
- LastIdx = -1;
- Size = DefaultFilterSize;
- };
-
- // Create a new filter with size i
- SensorFilter(int i)
- {
- OVR_ASSERT(i <= MaxFilterSize);
- LastIdx = -1;
- Size = i;
- };
-
-
- // Create a new element to the filter
- void AddElement (const Vector3f &e)
- {
- if (LastIdx == Size - 1)
- LastIdx = 0;
- else
- LastIdx++;
-
- Elements[LastIdx] = e;
- };
-
- // Get element i. 0 is the most recent, 1 is one step ago, 2 is two steps ago, ...
- Vector3f GetPrev(int i) const
- {
- OVR_ASSERT(i >= 0); //
- int idx = (LastIdx - i);
- if (idx < 0) // Fix the wraparound case
- idx += Size;
- OVR_ASSERT(idx >= 0); // Multiple wraparounds not allowed
- return Elements[idx];
- };
-
- // Simple statistics
- Vector3f Total() const;
- Vector3f Mean() const;
- Vector3f Median() const;
- Vector3f Variance() const; // The diagonal of covariance matrix
- Matrix4f Covariance() const;
- Vector3f PearsonCoefficient() const;
-
- // A popular family of smoothing filters and smoothed derivatives
- Vector3f SavitzkyGolaySmooth8() const;
- Vector3f SavitzkyGolayDerivative4() const;
- Vector3f SavitzkyGolayDerivative5() const;
- Vector3f SavitzkyGolayDerivative12() const;
- Vector3f SavitzkyGolayDerivativeN(int n) const;
-
- ~SensorFilter() {};
-};
-
-} //namespace OVR
-
-#endif // OVR_SensorFilter_h
+/************************************************************************************
+
+PublicHeader: OVR.h
+Filename : OVR_SensorFilter.h
+Content : Basic filtering of sensor data
+Created : March 7, 2013
+Authors : Steve LaValle, Anna Yershova
+
+Copyright : Copyright 2012 Oculus VR, Inc. All Rights reserved.
+
+Use of this software is subject to the terms of the Oculus license
+agreement provided at the time of installation or download, or which
+otherwise accompanies this software in either electronic or hard copy form.
+
+*************************************************************************************/
+
+#ifndef OVR_SensorFilter_h
+#define OVR_SensorFilter_h
+
+#include "Kernel/OVR_Math.h"
+
+
+namespace OVR {
+
+// This class maintains a sliding window of sensor data taken over time and implements
+// various simple filters, most of which are linear functions of the data history.
+class SensorFilter
+{
+ enum
+ {
+ MaxFilterSize = 100,
+ DefaultFilterSize = 20
+ };
+
+private:
+ int LastIdx; // The index of the last element that was added to the array
+ int Size; // The window size (number of elements)
+ Vector3f Elements[MaxFilterSize];
+
+public:
+ // Create a new filter with default size
+ SensorFilter()
+ {
+ LastIdx = -1;
+ Size = DefaultFilterSize;
+ };
+
+ // Create a new filter with size i
+ SensorFilter(int i)
+ {
+ OVR_ASSERT(i <= MaxFilterSize);
+ LastIdx = -1;
+ Size = i;
+ };
+
+
+ // Create a new element to the filter
+ void AddElement (const Vector3f &e)
+ {
+ if (LastIdx == Size - 1)
+ LastIdx = 0;
+ else
+ LastIdx++;
+
+ Elements[LastIdx] = e;
+ };
+
+ // Get element i. 0 is the most recent, 1 is one step ago, 2 is two steps ago, ...
+ Vector3f GetPrev(int i) const
+ {
+ OVR_ASSERT(i >= 0); //
+ int idx = (LastIdx - i);
+ if (idx < 0) // Fix the wraparound case
+ idx += Size;
+ OVR_ASSERT(idx >= 0); // Multiple wraparounds not allowed
+ return Elements[idx];
+ };
+
+ // Simple statistics
+ Vector3f Total() const;
+ Vector3f Mean() const;
+ Vector3f Median() const;
+ Vector3f Variance() const; // The diagonal of covariance matrix
+ Matrix4f Covariance() const;
+ Vector3f PearsonCoefficient() const;
+
+ // A popular family of smoothing filters and smoothed derivatives
+ Vector3f SavitzkyGolaySmooth8() const;
+ Vector3f SavitzkyGolayDerivative4() const;
+ Vector3f SavitzkyGolayDerivative5() const;
+ Vector3f SavitzkyGolayDerivative12() const;
+ Vector3f SavitzkyGolayDerivativeN(int n) const;
+
+ ~SensorFilter() {};
+};
+
+} //namespace OVR
+
+#endif // OVR_SensorFilter_h
diff --git a/LibOVR/Src/OVR_SensorFusion.cpp b/LibOVR/Src/OVR_SensorFusion.cpp
index 78dd128..a4c5809 100644
--- a/LibOVR/Src/OVR_SensorFusion.cpp
+++ b/LibOVR/Src/OVR_SensorFusion.cpp
@@ -1,378 +1,435 @@
-/************************************************************************************
-
-Filename : OVR_SensorFusion.cpp
-Content : Methods that determine head orientation from sensor data over time
-Created : October 9, 2012
-Authors : Michael Antonov, Steve LaValle
-
-Copyright : Copyright 2012 Oculus VR, Inc. All Rights reserved.
-
-Use of this software is subject to the terms of the Oculus license
-agreement provided at the time of installation or download, or which
-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"
-
-namespace OVR {
-
-//-------------------------------------------------------------------------------------
-// ***** Sensor Fusion
-
-SensorFusion::SensorFusion(SensorDevice* sensor)
- : Handler(getThis()), pDelegate(0),
- Gain(0.05f), YawMult(1), EnableGravity(true), Stage(0), DeltaT(0.001f),
- EnablePrediction(false), PredictionDT(0.03f),
- FRawMag(10), FAccW(20), FAngV(20),
- TiltCondCount(0), TiltErrorAngle(0),
- TiltErrorAxis(0,1,0),
- MagCondCount(0), MagReady(false), MagCalibrated(false), MagReferenced(false),
- MagRefQ(0, 0, 0, 1), MagRefM(0), MagRefYaw(0), YawErrorAngle(0), MagRefDistance(0.15f),
- YawErrorCount(0), YawCorrectionActivated(false), YawCorrectionInProgress(false),
- EnableYawCorrection(false)
-{
- if (sensor)
- AttachToSensor(sensor);
- MagCalibrationMatrix.SetIdentity();
-}
-
-SensorFusion::~SensorFusion()
-{
-}
-
-
-bool SensorFusion::AttachToSensor(SensorDevice* sensor)
-{
-
- if (sensor != NULL)
- {
- MessageHandler* pCurrentHandler = sensor->GetMessageHandler();
-
- if (pCurrentHandler == &Handler)
- {
- Reset();
- return true;
- }
-
- if (pCurrentHandler != NULL)
- {
- OVR_DEBUG_LOG(
- ("SensorFusion::AttachToSensor failed - sensor %p already has handler", sensor));
- return false;
- }
- }
-
- if (Handler.IsHandlerInstalled())
- {
- Handler.RemoveHandlerFromDevices();
- }
-
- if (sensor != NULL)
- {
- sensor->SetMessageHandler(&Handler);
- }
-
- Reset();
- return true;
-}
-
-
-
-
-void SensorFusion::handleMessage(const MessageBodyFrame& msg)
-{
- if (msg.Type != Message_BodyFrame)
- return;
-
- // Put the sensor readings into convenient local variables
- Vector3f angVel = msg.RotationRate;
- Vector3f rawAccel = msg.Acceleration;
- Vector3f mag = msg.MagneticField;
-
- // Set variables accessible through the class API
- DeltaT = msg.TimeDelta;
- AngV = msg.RotationRate;
- AngV.y *= YawMult; // Warning: If YawMult != 1, then AngV is not true angular velocity
- A = rawAccel;
-
- // Allow external access to uncalibrated magnetometer values
- RawMag = mag;
-
- // Apply the calibration parameters to raw mag
- if (HasMagCalibration())
- {
- mag.x += MagCalibrationMatrix.M[0][3];
- mag.y += MagCalibrationMatrix.M[1][3];
- mag.z += MagCalibrationMatrix.M[2][3];
- }
-
- // Provide external access to calibrated mag values
- // (if the mag is not calibrated, then the raw value is returned)
- CalMag = mag;
-
- float angVelLength = angVel.Length();
- float accLength = rawAccel.Length();
-
-
- // Acceleration in the world frame (Q is current HMD orientation)
- Vector3f accWorld = Q.Rotate(rawAccel);
-
- // Keep track of time
- Stage++;
- float currentTime = Stage * DeltaT; // Assumes uniform time spacing
-
- // Insert current sensor data into filter history
- FRawMag.AddElement(RawMag);
- FAccW.AddElement(accWorld);
- FAngV.AddElement(angVel);
-
- // Update orientation Q based on gyro outputs. This technique is
- // based on direct properties of the angular velocity vector:
- // Its direction is the current rotation axis, and its magnitude
- // is the rotation rate (rad/sec) about that axis. Our sensor
- // sampling rate is so fast that we need not worry about integral
- // approximation error (not yet, anyway).
- if (angVelLength > 0.0f)
- {
- Vector3f rotAxis = angVel / angVelLength;
- float halfRotAngle = angVelLength * DeltaT * 0.5f;
- float sinHRA = sin(halfRotAngle);
- Quatf deltaQ(rotAxis.x*sinHRA, rotAxis.y*sinHRA, rotAxis.z*sinHRA, cos(halfRotAngle));
-
- Q = Q * deltaQ;
- }
-
- // The quaternion magnitude may slowly drift due to numerical error,
- // so it is periodically normalized.
- if (Stage % 5000 == 0)
- Q.Normalize();
-
- // Maintain the uncorrected orientation for later use by predictive filtering
- QUncorrected = Q;
-
- // Perform tilt correction using the accelerometer data. This enables
- // drift errors in pitch and roll to be corrected. Note that yaw cannot be corrected
- // because the rotation axis is parallel to the gravity vector.
- if (EnableGravity)
- {
- // Correcting for tilt error by using accelerometer data
- const float gravityEpsilon = 0.4f;
- const float angVelEpsilon = 0.1f; // Relatively slow rotation
- const int tiltPeriod = 50; // Req'd time steps of stability
- const float maxTiltError = 0.05f;
- const float minTiltError = 0.01f;
-
- // This condition estimates whether the only measured acceleration is due to gravity
- // (the Rift is not linearly accelerating). It is often wrong, but tends to average
- // out well over time.
- if ((fabs(accLength - 9.81f) < gravityEpsilon) &&
- (angVelLength < angVelEpsilon))
- TiltCondCount++;
- else
- TiltCondCount = 0;
-
- // After stable measurements have been taken over a sufficiently long period,
- // estimate the amount of tilt error and calculate the tilt axis for later correction.
- if (TiltCondCount >= tiltPeriod)
- { // Update TiltErrorEstimate
- TiltCondCount = 0;
- // Use an average value to reduce noice (could alternatively use an LPF)
- Vector3f accWMean = FAccW.Mean();
- // Project the acceleration vector into the XZ plane
- Vector3f xzAcc = Vector3f(accWMean.x, 0.0f, accWMean.z);
- // The unit normal of xzAcc will be the rotation axis for tilt correction
- Vector3f tiltAxis = Vector3f(xzAcc.z, 0.0f, -xzAcc.x).Normalized();
- Vector3f yUp = Vector3f(0.0f, 1.0f, 0.0f);
- // This is the amount of rotation
- float tiltAngle = yUp.Angle(accWMean);
- // Record values if the tilt error is intolerable
- if (tiltAngle > maxTiltError)
- {
- TiltErrorAngle = tiltAngle;
- TiltErrorAxis = tiltAxis;
- }
- }
-
- // This part performs the actual tilt correction as needed
- if (TiltErrorAngle > minTiltError)
- {
- if ((TiltErrorAngle > 0.4f)&&(Stage < 8000))
- { // Tilt completely to correct orientation
- Q = Quatf(TiltErrorAxis, -TiltErrorAngle) * Q;
- TiltErrorAngle = 0.0f;
- }
- else
- {
- //LogText("Performing tilt correction - Angle: %f Axis: %f %f %f\n",
- // TiltErrorAngle,TiltErrorAxis.x,TiltErrorAxis.y,TiltErrorAxis.z);
- //float deltaTiltAngle = -Gain*TiltErrorAngle*0.005f;
- // This uses agressive correction steps while your head is moving fast
- float deltaTiltAngle = -Gain*TiltErrorAngle*0.005f*(5.0f*angVelLength+1.0f);
- // Incrementally "untilt" by a small step size
- Q = Quatf(TiltErrorAxis, deltaTiltAngle) * Q;
- TiltErrorAngle += deltaTiltAngle;
- }
- }
- }
-
- // Yaw drift correction based on magnetometer data. This corrects the part of the drift
- // that the accelerometer cannot handle.
- // This will only work if the magnetometer has been enabled, calibrated, and a reference
- // point has been set.
- const float maxAngVelLength = 3.0f;
- const int magWindow = 5;
- const float yawErrorMax = 0.1f;
- const float yawErrorMin = 0.01f;
- const int yawErrorCountLimit = 50;
- const float yawRotationStep = 0.00002f;
-
- if (angVelLength < maxAngVelLength)
- MagCondCount++;
- else
- MagCondCount = 0;
-
- YawCorrectionInProgress = false;
- if (EnableYawCorrection && MagReady && (currentTime > 2.0f) && (MagCondCount >= magWindow) &&
- (Q.Distance(MagRefQ) < MagRefDistance))
- {
- // Use rotational invariance to bring reference mag value into global frame
- Vector3f grefmag = MagRefQ.Rotate(GetCalibratedMagValue(MagRefM));
- // Bring current (averaged) mag reading into global frame
- Vector3f gmag = Q.Rotate(GetCalibratedMagValue(FRawMag.Mean()));
- // Calculate the reference yaw in the global frame
- float gryaw = atan2(grefmag.x,grefmag.z);
- // Calculate the current yaw in the global frame
- float gyaw = atan2(gmag.x,gmag.z);
- //LogText("Yaw error estimate: %f\n",YawErrorAngle);
- // The difference between reference and current yaws is the perceived error
- YawErrorAngle = AngleDifference(gyaw,gryaw);
- // If the perceived error is large, keep count
- if ((fabs(YawErrorAngle) > yawErrorMax) && (!YawCorrectionActivated))
- YawErrorCount++;
- // After enough iterations of high perceived error, start the correction process
- if (YawErrorCount > yawErrorCountLimit)
- YawCorrectionActivated = true;
- // If the perceived error becomes small, turn off the yaw correction
- if ((fabs(YawErrorAngle) < yawErrorMin) && YawCorrectionActivated)
- {
- YawCorrectionActivated = false;
- YawErrorCount = 0;
- }
- // Perform the actual yaw correction, due to previously detected, large yaw error
- if (YawCorrectionActivated)
- {
- YawCorrectionInProgress = true;
- int sign = (YawErrorAngle > 0.0f) ? 1 : -1;
- // Incrementally "unyaw" by a small step size
- Q = Quatf(Vector3f(0.0f,1.0f,0.0f), -yawRotationStep * sign) * Q;
- }
- }
-}
-
-
- // This is a simple predictive filter based only on extrapolating the smoothed, current angular velocity.
- // Note that both QP (the predicted future orientation) and Q (the current orientation) are both maintained.
-Quatf SensorFusion::GetPredictedOrientation()
-{
- Lock::Locker lockScope(Handler.GetHandlerLock());
- Quatf qP = QUncorrected;
- if (EnablePrediction) {
-#if 1
- Vector3f angVelF = FAngV.SavitzkyGolaySmooth8();
- float angVelFL = angVelF.Length();
-
- if (angVelFL > 0.001f)
- {
- Vector3f rotAxisP = angVelF / angVelFL;
- float halfRotAngleP = angVelFL * PredictionDT * 0.5f;
- float sinaHRAP = sin(halfRotAngleP);
- Quatf deltaQP(rotAxisP.x*sinaHRAP, rotAxisP.y*sinaHRAP,
- rotAxisP.z*sinaHRAP, cos(halfRotAngleP));
- qP = QUncorrected * deltaQP;
- }
-#else
- Quatd qpd = Quatd(Q.x,Q.y,Q.z,Q.w);
- int predictionStages = (int)(PredictionDT / DeltaT);
- 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);
- for (int i = 0; i < predictionStages; i++)
- {
- double angVelLengthd = avkd.Length();
- Vector3d rotAxisd = avkd / angVelLengthd;
- double halfRotAngled = angVelLengthd * DeltaT * 0.5;
- double sinHRAd = sin(halfRotAngled);
- Quatd deltaQd = Quatd(rotAxisd.x*sinHRAd, rotAxisd.y*sinHRAd, rotAxisd.z*sinHRAd,
- cos(halfRotAngled));
- qpd = qpd * deltaQd;
- // Update vel
- avkd += aad;
- }
- qP = Quatf((float)qpd.x,(float)qpd.y,(float)qpd.z,(float)qpd.w);
-#endif
- }
- return qP;
-}
-
-
-Vector3f SensorFusion::GetCalibratedMagValue(const Vector3f& rawMag) const
-{
- Vector3f mag = rawMag;
- OVR_ASSERT(HasMagCalibration());
- mag.x += MagCalibrationMatrix.M[0][3];
- mag.y += MagCalibrationMatrix.M[1][3];
- mag.z += MagCalibrationMatrix.M[2][3];
- return mag;
-}
-
-
-void SensorFusion::SetMagReference(const Quatf& q, const Vector3f& rawMag)
-{
- MagRefQ = q;
- MagRefM = rawMag;
-
- float pitch, roll, yaw;
- Q.GetEulerAngles<Axis_X, Axis_Z, Axis_Y>(&pitch, &roll, &yaw);
- MagRefYaw = yaw;
- MagReferenced = true;
- if (MagCalibrated)
- MagReady = true;
-}
-
-
-float SensorFusion::AngleDifference(float theta1, float theta2)
-{
- float x = theta1 - theta2;
- if (x > Math<float>::Pi)
- return x - Math<float>::TwoPi;
- if (x < -Math<float>::Pi)
- return x + Math<float>::TwoPi;
- return x;
-}
-
-
-SensorFusion::BodyFrameHandler::~BodyFrameHandler()
-{
- RemoveHandlerFromDevices();
-}
-
-void SensorFusion::BodyFrameHandler::OnMessage(const Message& msg)
-{
- if (msg.Type == Message_BodyFrame)
- pFusion->handleMessage(static_cast<const MessageBodyFrame&>(msg));
- if (pFusion->pDelegate)
- pFusion->pDelegate->OnMessage(msg);
-}
-
-bool SensorFusion::BodyFrameHandler::SupportsMessageType(MessageType type) const
-{
- return (type == Message_BodyFrame);
-}
-
-
-} // namespace OVR
-
+/************************************************************************************
+
+Filename : OVR_SensorFusion.cpp
+Content : Methods that determine head orientation from sensor data over time
+Created : October 9, 2012
+Authors : Michael Antonov, Steve LaValle
+
+Copyright : Copyright 2012 Oculus VR, Inc. All Rights reserved.
+
+Use of this software is subject to the terms of the Oculus license
+agreement provided at the time of installation or download, or which
+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"
+
+namespace OVR {
+
+//-------------------------------------------------------------------------------------
+// ***** Sensor Fusion
+
+SensorFusion::SensorFusion(SensorDevice* sensor)
+ : Handler(getThis()), pDelegate(0),
+ Gain(0.05f), YawMult(1), EnableGravity(true), Stage(0), RunningTime(0), DeltaT(0.001f),
+ EnablePrediction(true), PredictionDT(0.03f), PredictionTimeIncrement(0.001f),
+ FRawMag(10), FAccW(20), FAngV(20),
+ TiltCondCount(0), TiltErrorAngle(0),
+ TiltErrorAxis(0,1,0),
+ 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)
+{
+ if (sensor)
+ AttachToSensor(sensor);
+ MagCalibrationMatrix.SetIdentity();
+}
+
+SensorFusion::~SensorFusion()
+{
+}
+
+
+bool SensorFusion::AttachToSensor(SensorDevice* sensor)
+{
+
+ if (sensor != NULL)
+ {
+ MessageHandler* pCurrentHandler = sensor->GetMessageHandler();
+
+ if (pCurrentHandler == &Handler)
+ {
+ Reset();
+ return true;
+ }
+
+ if (pCurrentHandler != NULL)
+ {
+ OVR_DEBUG_LOG(
+ ("SensorFusion::AttachToSensor failed - sensor %p already has handler", sensor));
+ return false;
+ }
+ }
+
+ if (Handler.IsHandlerInstalled())
+ {
+ Handler.RemoveHandlerFromDevices();
+ }
+
+ if (sensor != NULL)
+ {
+ sensor->SetMessageHandler(&Handler);
+ }
+
+ Reset();
+ return true;
+}
+
+
+ // Resets the current orientation
+void SensorFusion::Reset()
+{
+ Lock::Locker lockScope(Handler.GetHandlerLock());
+ Q = Quatf();
+ QUncorrected = Quatf();
+ Stage = 0;
+ RunningTime = 0;
+ MagNumReferences = 0;
+ MagHasNearbyReference = false;
+}
+
+
+void SensorFusion::handleMessage(const MessageBodyFrame& msg)
+{
+ if (msg.Type != Message_BodyFrame)
+ return;
+
+ // Put the sensor readings into convenient local variables
+ Vector3f angVel = msg.RotationRate;
+ Vector3f rawAccel = msg.Acceleration;
+ Vector3f mag = msg.MagneticField;
+
+ // Set variables accessible through the class API
+ DeltaT = msg.TimeDelta;
+ AngV = msg.RotationRate;
+ AngV.y *= YawMult; // Warning: If YawMult != 1, then AngV is not true angular velocity
+ A = rawAccel;
+
+ // Allow external access to uncalibrated magnetometer values
+ RawMag = mag;
+
+ // Apply the calibration parameters to raw mag
+ if (HasMagCalibration())
+ {
+ mag.x += MagCalibrationMatrix.M[0][3];
+ mag.y += MagCalibrationMatrix.M[1][3];
+ mag.z += MagCalibrationMatrix.M[2][3];
+ }
+
+ // Provide external access to calibrated mag values
+ // (if the mag is not calibrated, then the raw value is returned)
+ CalMag = mag;
+
+ float angVelLength = angVel.Length();
+ float accLength = rawAccel.Length();
+
+
+ // Acceleration in the world frame (Q is current HMD orientation)
+ Vector3f accWorld = Q.Rotate(rawAccel);
+
+ // Keep track of time
+ Stage++;
+ RunningTime += DeltaT;
+
+ // Insert current sensor data into filter history
+ FRawMag.AddElement(RawMag);
+ FAccW.AddElement(accWorld);
+ FAngV.AddElement(angVel);
+
+ // Update orientation Q based on gyro outputs. This technique is
+ // based on direct properties of the angular velocity vector:
+ // Its direction is the current rotation axis, and its magnitude
+ // is the rotation rate (rad/sec) about that axis. Our sensor
+ // sampling rate is so fast that we need not worry about integral
+ // approximation error (not yet, anyway).
+ if (angVelLength > 0.0f)
+ {
+ Vector3f rotAxis = angVel / angVelLength;
+ float halfRotAngle = angVelLength * DeltaT * 0.5f;
+ float sinHRA = sin(halfRotAngle);
+ Quatf deltaQ(rotAxis.x*sinHRA, rotAxis.y*sinHRA, rotAxis.z*sinHRA, cos(halfRotAngle));
+
+ Q = Q * deltaQ;
+ }
+
+ // The quaternion magnitude may slowly drift due to numerical error,
+ // so it is periodically normalized.
+ if (Stage % 5000 == 0)
+ Q.Normalize();
+
+ // Maintain the uncorrected orientation for later use by predictive filtering
+ QUncorrected = Q;
+
+ // Perform tilt correction using the accelerometer data. This enables
+ // drift errors in pitch and roll to be corrected. Note that yaw cannot be corrected
+ // because the rotation axis is parallel to the gravity vector.
+ if (EnableGravity)
+ {
+ // Correcting for tilt error by using accelerometer data
+ const float gravityEpsilon = 0.4f;
+ const float angVelEpsilon = 0.1f; // Relatively slow rotation
+ const int tiltPeriod = 50; // Required time steps of stability
+ const float maxTiltError = 0.05f;
+ const float minTiltError = 0.01f;
+
+ // This condition estimates whether the only measured acceleration is due to gravity
+ // (the Rift is not linearly accelerating). It is often wrong, but tends to average
+ // out well over time.
+ if ((fabs(accLength - 9.81f) < gravityEpsilon) &&
+ (angVelLength < angVelEpsilon))
+ TiltCondCount++;
+ else
+ TiltCondCount = 0;
+
+ // After stable measurements have been taken over a sufficiently long period,
+ // estimate the amount of tilt error and calculate the tilt axis for later correction.
+ if (TiltCondCount >= tiltPeriod)
+ { // Update TiltErrorEstimate
+ TiltCondCount = 0;
+ // Use an average value to reduce noise (could alternatively use an LPF)
+ Vector3f accWMean = FAccW.Mean();
+ // Project the acceleration vector into the XZ plane
+ Vector3f xzAcc = Vector3f(accWMean.x, 0.0f, accWMean.z);
+ // The unit normal of xzAcc will be the rotation axis for tilt correction
+ Vector3f tiltAxis = Vector3f(xzAcc.z, 0.0f, -xzAcc.x).Normalized();
+ Vector3f yUp = Vector3f(0.0f, 1.0f, 0.0f);
+ // This is the amount of rotation
+ float tiltAngle = yUp.Angle(accWMean);
+ // Record values if the tilt error is intolerable
+ if (tiltAngle > maxTiltError)
+ {
+ TiltErrorAngle = tiltAngle;
+ TiltErrorAxis = tiltAxis;
+ }
+ }
+
+ // This part performs the actual tilt correction as needed
+ if (TiltErrorAngle > minTiltError)
+ {
+ if ((TiltErrorAngle > 0.4f)&&(RunningTime < 8.0f))
+ { // Tilt completely to correct orientation
+ Q = Quatf(TiltErrorAxis, -TiltErrorAngle) * Q;
+ TiltErrorAngle = 0.0f;
+ }
+ else
+ {
+ //LogText("Performing tilt correction - Angle: %f Axis: %f %f %f\n",
+ // TiltErrorAngle,TiltErrorAxis.x,TiltErrorAxis.y,TiltErrorAxis.z);
+ //float deltaTiltAngle = -Gain*TiltErrorAngle*0.005f;
+ // This uses aggressive correction steps while your head is moving fast
+ float deltaTiltAngle = -Gain*TiltErrorAngle*0.005f*(5.0f*angVelLength+1.0f);
+ // Incrementally "un-tilt" by a small step size
+ Q = Quatf(TiltErrorAxis, deltaTiltAngle) * Q;
+ TiltErrorAngle += deltaTiltAngle;
+ }
+ }
+ }
+
+ // Yaw drift correction based on magnetometer data. This corrects the part of the drift
+ // that the accelerometer cannot handle.
+ // This will only work if the magnetometer has been enabled, calibrated, and a reference
+ // point has been set.
+ const float maxAngVelLength = 3.0f;
+ const int magWindow = 5;
+ const float yawErrorMax = 0.1f;
+ const float yawErrorMin = 0.01f;
+ const int yawErrorCountLimit = 50;
+ const float yawRotationStep = 0.00002f;
+
+ if (angVelLength < maxAngVelLength)
+ MagCondCount++;
+ else
+ MagCondCount = 0;
+
+ // Find, create, and utilize reference points for the magnetometer
+ // Need to be careful not to set reference points while there is significant tilt error
+ if ((EnableYawCorrection && MagCalibrated)&&(RunningTime > 10.0f)&&(TiltErrorAngle < 0.2f))
+ {
+ if (MagNumReferences == 0)
+ {
+ SetMagReference(); // Use the current direction
+ }
+ else if (Q.Distance(MagRefQ) > MagRefDistance)
+ {
+ MagHasNearbyReference = false;
+ float bestDist = 100000.0f;
+ int bestNdx = 0;
+ float dist;
+ for (int i = 0; i < MagNumReferences; i++)
+ {
+ dist = Q.Distance(MagRefTableQ[i]);
+ if (dist < bestDist)
+ {
+ bestNdx = i;
+ bestDist = dist;
+ }
+ }
+
+ if (bestDist < MagRefDistance)
+ {
+ MagHasNearbyReference = true;
+ MagRefQ = MagRefTableQ[bestNdx];
+ MagRefM = MagRefTableM[bestNdx];
+ MagRefYaw = MagRefTableYaw[bestNdx];
+ //LogText("Using reference %d\n",bestNdx);
+ }
+ else if (MagNumReferences < MagMaxReferences)
+ SetMagReference();
+ }
+ }
+
+ YawCorrectionInProgress = false;
+ if (EnableYawCorrection && MagCalibrated && (RunningTime > 2.0f) && (MagCondCount >= magWindow) &&
+ MagHasNearbyReference)
+ {
+ // Use rotational invariance to bring reference mag value into global frame
+ Vector3f grefmag = MagRefQ.Rotate(GetCalibratedMagValue(MagRefM));
+ // Bring current (averaged) mag reading into global frame
+ Vector3f gmag = Q.Rotate(GetCalibratedMagValue(FRawMag.Mean()));
+ // Calculate the reference yaw in the global frame
+ Anglef gryaw = Anglef(atan2(grefmag.x,grefmag.z));
+ // Calculate the current yaw in the global frame
+ Anglef gyaw = Anglef(atan2(gmag.x,gmag.z));
+ // The difference between reference and current yaws is the perceived error
+ Anglef YawErrorAngle = gyaw - gryaw;
+
+ //LogText("Yaw error estimate: %f\n",YawErrorAngle.Get());
+ // If the perceived error is large, keep count
+ if ((YawErrorAngle.Abs() > yawErrorMax) && (!YawCorrectionActivated))
+ YawErrorCount++;
+ // After enough iterations of high perceived error, start the correction process
+ if (YawErrorCount > yawErrorCountLimit)
+ YawCorrectionActivated = true;
+ // If the perceived error becomes small, turn off the yaw correction
+ if ((YawErrorAngle.Abs() < yawErrorMin) && YawCorrectionActivated)
+ {
+ YawCorrectionActivated = false;
+ YawErrorCount = 0;
+ }
+
+ // Perform the actual yaw correction, due to previously detected, large yaw error
+ if (YawCorrectionActivated)
+ {
+ YawCorrectionInProgress = true;
+ // Incrementally "unyaw" by a small step size
+ Q = Quatf(Vector3f(0.0f,1.0f,0.0f), -yawRotationStep * YawErrorAngle.Sign()) * Q;
+ }
+ }
+}
+
+
+// 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.
+Quatf SensorFusion::GetPredictedOrientation(float pdt)
+{
+ Lock::Locker lockScope(Handler.GetHandlerLock());
+ Quatf qP = QUncorrected;
+
+ if (EnablePrediction)
+ {
+#if 1
+ // This method assumes a constant angular velocity
+ Vector3f angVelF = FAngV.SavitzkyGolaySmooth8();
+ float angVelFL = angVelF.Length();
+
+ if (angVelFL > 0.001f)
+ {
+ Vector3f rotAxisP = angVelF / angVelFL;
+ float halfRotAngleP = angVelFL * pdt * 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;
+}
+
+
+Vector3f SensorFusion::GetCalibratedMagValue(const Vector3f& rawMag) const
+{
+ Vector3f mag = rawMag;
+ OVR_ASSERT(HasMagCalibration());
+ mag.x += MagCalibrationMatrix.M[0][3];
+ mag.y += MagCalibrationMatrix.M[1][3];
+ mag.z += MagCalibrationMatrix.M[2][3];
+ return mag;
+}
+
+
+void SensorFusion::SetMagReference(const Quatf& q, const Vector3f& rawMag)
+{
+ if (MagNumReferences < MagMaxReferences)
+ {
+ MagRefTableQ[MagNumReferences] = q;
+ MagRefTableM[MagNumReferences] = rawMag; //FRawMag.Mean();
+
+ //LogText("Inserting reference %d\n",MagNumReferences);
+
+ MagRefQ = q;
+ MagRefM = rawMag;
+
+ float pitch, roll, yaw;
+ Quatf q2 = q;
+ q2.GetEulerAngles<Axis_X, Axis_Z, Axis_Y>(&pitch, &roll, &yaw);
+ MagRefTableYaw[MagNumReferences] = yaw;
+ MagRefYaw = yaw;
+
+ MagNumReferences++;
+
+ MagHasNearbyReference = true;
+ }
+}
+
+
+SensorFusion::BodyFrameHandler::~BodyFrameHandler()
+{
+ RemoveHandlerFromDevices();
+}
+
+void SensorFusion::BodyFrameHandler::OnMessage(const Message& msg)
+{
+ if (msg.Type == Message_BodyFrame)
+ pFusion->handleMessage(static_cast<const MessageBodyFrame&>(msg));
+ if (pFusion->pDelegate)
+ pFusion->pDelegate->OnMessage(msg);
+}
+
+bool SensorFusion::BodyFrameHandler::SupportsMessageType(MessageType type) const
+{
+ return (type == Message_BodyFrame);
+}
+
+
+} // namespace OVR
+
diff --git a/LibOVR/Src/OVR_SensorFusion.h b/LibOVR/Src/OVR_SensorFusion.h
index 8b88ea2..adfe780 100644
--- a/LibOVR/Src/OVR_SensorFusion.h
+++ b/LibOVR/Src/OVR_SensorFusion.h
@@ -1,268 +1,252 @@
-/************************************************************************************
-
-PublicHeader: OVR.h
-Filename : OVR_SensorFusion.h
-Content : Methods that determine head orientation from sensor data over time
-Created : October 9, 2012
-Authors : Michael Antonov, Steve LaValle
-
-Copyright : Copyright 2012 Oculus VR, Inc. All Rights reserved.
-
-Use of this software is subject to the terms of the Oculus license
-agreement provided at the time of installation or download, or which
-otherwise accompanies this software in either electronic or hard copy form.
-
-*************************************************************************************/
-
-#ifndef OVR_SensorFusion_h
-#define OVR_SensorFusion_h
-
-#include "OVR_Device.h"
-#include "OVR_SensorFilter.h"
-
-namespace OVR {
-
-//-------------------------------------------------------------------------------------
-// ***** SensorFusion
-
-// SensorFusion class accumulates Sensor notification messages to keep track of
-// orientation, which involves integrating the gyro and doing correction with gravity.
-// Orientation is reported as a quaternion, from which users can obtain either the
-// rotation matrix or Euler angles.
-//
-// The class can operate in two ways:
-// - By user manually passing MessageBodyFrame messages to the OnMessage() function.
-// - By attaching SensorFusion to a SensorDevice, in which case it will
-// automatically handle notifications from that device.
-
-class SensorFusion : public NewOverrideBase
-{
-public:
- SensorFusion(SensorDevice* sensor = 0);
- ~SensorFusion();
-
- // Attaches this SensorFusion to a sensor device, from which it will receive
- // notification messages. If a sensor is attached, manual message notification
- // is not necessary. Calling this function also resets SensorFusion state.
- bool AttachToSensor(SensorDevice* sensor);
-
- // Returns true if this Sensor fusion object is attached to a sensor.
- bool IsAttachedToSensor() const { return Handler.IsHandlerInstalled(); }
-
- void SetGravityEnabled(bool enableGravity) { EnableGravity = enableGravity; }
-
- bool IsGravityEnabled() const { return EnableGravity;}
-
- void SetYawCorrectionEnabled(bool enableYawCorrection) { EnableYawCorrection = enableYawCorrection; }
-
- // Yaw correction is set up to work
- bool IsYawCorrectionEnabled() const { return EnableYawCorrection;}
-
- // Yaw correction is currently working (forcing a corrective yaw rotation)
- bool IsYawCorrectionInProgress() const { return YawCorrectionInProgress;}
-
- // Store the calibration matrix for the magnetometer
- void SetMagCalibration(const Matrix4f& m)
- {
- MagCalibrationMatrix = m;
- MagCalibrated = true;
- if (MagReferenced)
- MagReady = true;
- }
-
- // True only if the mag has calibration values stored
- bool HasMagCalibration() const { return MagCalibrated;}
-
- // Force the mag into the uncalibrated state
- void ClearMagCalibration()
- {
- MagCalibrated = false;
- MagReady = false;
- }
-
- // 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);
- // Default to current HMD orientation
- void SetMagReference() { SetMagReference(Q, RawMag); }
-
- bool HasMagReference() const { return MagReferenced; }
-
- void ClearMagReference()
- {
- MagReferenced = false;
- MagReady = false;
- }
-
- bool IsMagReady() const { return MagReady; }
-
- 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();
-
- // 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 GetYawErrorAngle() const
- {
- return YawErrorAngle;
- }
- // For later
- //Vector3f GetGravity() const;
-
- // Resets the current orientation
- void Reset()
- {
- Lock::Locker lockScope(Handler.GetHandlerLock());
- Q = Quatf();
- QUncorrected = Quatf();
-
- Stage = 0;
- }
-
- // Configuration
-
- // 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; }
-
- 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; }
-
- // Methods for magnetometer calibration
- static float AngleDifference(float theta1, float theta2);
- static Vector3f CalculateSphereCenter(Vector3f p1, Vector3f p2,
- Vector3f p3, Vector3f p4);
-
-
-private:
- SensorFusion* getThis() { return this; }
-
- // Internal handler for messages; bypasses error checking.
- void handleMessage(const MessageBodyFrame& msg);
-
- class BodyFrameHandler : public MessageHandler
- {
- SensorFusion* pFusion;
- public:
- BodyFrameHandler(SensorFusion* fusion) : pFusion(fusion) { }
- ~BodyFrameHandler();
-
- virtual void OnMessage(const Message& msg);
- virtual bool SupportsMessageType(MessageType type) const;
- };
-
- Quatf Q;
- Quatf QUncorrected;
- Vector3f A;
- Vector3f AngV;
- Vector3f CalMag;
- Vector3f RawMag;
- unsigned int Stage;
- float DeltaT;
- BodyFrameHandler Handler;
- MessageHandler* pDelegate;
- float Gain;
- float YawMult;
- volatile bool EnableGravity;
-
- bool EnablePrediction;
- float PredictionDT;
-
- SensorFilter FRawMag;
- SensorFilter FAccW;
- SensorFilter FAngV;
-
- int TiltCondCount;
- float TiltErrorAngle;
- Vector3f TiltErrorAxis;
-
- bool EnableYawCorrection;
- Matrix4f MagCalibrationMatrix;
- bool MagCalibrated;
- int MagCondCount;
- bool MagReferenced;
- float MagRefDistance;
- bool MagReady;
- Quatf MagRefQ;
- Vector3f MagRefM;
- float MagRefYaw;
- float YawErrorAngle;
- int YawErrorCount;
- bool YawCorrectionInProgress;
- bool YawCorrectionActivated;
-
-};
-
-
-} // namespace OVR
-
-#endif
+/************************************************************************************
+
+PublicHeader: OVR.h
+Filename : OVR_SensorFusion.h
+Content : Methods that determine head orientation from sensor data over time
+Created : October 9, 2012
+Authors : Michael Antonov, Steve LaValle
+
+Copyright : Copyright 2012 Oculus VR, Inc. All Rights reserved.
+
+Use of this software is subject to the terms of the Oculus license
+agreement provided at the time of installation or download, or which
+otherwise accompanies this software in either electronic or hard copy form.
+
+*************************************************************************************/
+
+#ifndef OVR_SensorFusion_h
+#define OVR_SensorFusion_h
+
+#include "OVR_Device.h"
+#include "OVR_SensorFilter.h"
+
+namespace OVR {
+
+//-------------------------------------------------------------------------------------
+// ***** SensorFusion
+
+// SensorFusion class accumulates Sensor notification messages to keep track of
+// orientation, which involves integrating the gyro and doing correction with gravity.
+// Orientation is reported as a quaternion, from which users can obtain either the
+// rotation matrix or Euler angles.
+//
+// The class can operate in two ways:
+// - By user manually passing MessageBodyFrame messages to the OnMessage() function.
+// - 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();
+
+ // Attaches this SensorFusion to a sensor device, from which it will receive
+ // notification messages. If a sensor is attached, manual message notification
+ // is not necessary. Calling this function also resets SensorFusion state.
+ bool AttachToSensor(SensorDevice* sensor);
+
+ // Returns true if this Sensor fusion object is attached to a sensor.
+ bool IsAttachedToSensor() const { return Handler.IsHandlerInstalled(); }
+
+ void SetGravityEnabled(bool enableGravity) { EnableGravity = enableGravity; }
+
+ bool IsGravityEnabled() const { return EnableGravity;}
+
+ void SetYawCorrectionEnabled(bool enableYawCorrection) { EnableYawCorrection = enableYawCorrection; }
+
+ // Yaw correction is set up to work
+ bool IsYawCorrectionEnabled() const { return EnableYawCorrection;}
+
+ // Yaw correction is currently working (forcing a corrective yaw rotation)
+ bool IsYawCorrectionInProgress() const { return YawCorrectionInProgress;}
+
+ // Store the calibration matrix for the magnetometer
+ void SetMagCalibration(const Matrix4f& m)
+ {
+ MagCalibrationMatrix = m;
+ MagCalibrated = true;
+ }
+
+ // True only if the mag has calibration values stored
+ bool HasMagCalibration() const { return MagCalibrated;}
+
+ // Force the mag into the uncalibrated state
+ void ClearMagCalibration() { MagCalibrated = false; }
+
+ // These refer to reference points that associate mag readings with orientations
+ 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 GetYawErrorAngle() const
+ {
+ return YawErrorAngle;
+ }
+ // For later
+ //Vector3f GetGravity() const;
+
+ // Resets the current orientation
+ void Reset();
+
+ // Configuration
+
+ // 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; }
+
+ 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; }
+
+ // Internal handler for messages; bypasses error checking.
+ 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);
+ // Default to current HMD orientation
+ void SetMagReference() { SetMagReference(Q, RawMag); }
+
+ class BodyFrameHandler : public MessageHandler
+ {
+ SensorFusion* pFusion;
+ public:
+ BodyFrameHandler(SensorFusion* fusion) : pFusion(fusion) { }
+ ~BodyFrameHandler();
+
+ virtual void OnMessage(const Message& msg);
+ virtual bool SupportsMessageType(MessageType type) const;
+ };
+
+ Quatf Q;
+ Quatf QUncorrected;
+ Vector3f A;
+ Vector3f AngV;
+ Vector3f CalMag;
+ Vector3f RawMag;
+ unsigned int Stage;
+ float RunningTime;
+ float DeltaT;
+ BodyFrameHandler Handler;
+ MessageHandler* pDelegate;
+ float Gain;
+ float YawMult;
+ volatile bool EnableGravity;
+
+ bool EnablePrediction;
+ float PredictionDT;
+ float PredictionTimeIncrement;
+
+ SensorFilter FRawMag;
+ SensorFilter FAccW;
+ SensorFilter FAngV;
+
+ int TiltCondCount;
+ float TiltErrorAngle;
+ Vector3f TiltErrorAxis;
+
+ bool EnableYawCorrection;
+ Matrix4f MagCalibrationMatrix;
+ bool MagCalibrated;
+ int MagCondCount;
+ float MagRefDistance;
+ Quatf MagRefQ;
+ Vector3f MagRefM;
+ float MagRefYaw;
+ bool MagHasNearbyReference;
+ Quatf MagRefTableQ[MagMaxReferences];
+ Vector3f MagRefTableM[MagMaxReferences];
+ float MagRefTableYaw[MagMaxReferences];
+ int MagNumReferences;
+ float YawErrorAngle;
+ int YawErrorCount;
+ bool YawCorrectionInProgress;
+ bool YawCorrectionActivated;
+
+};
+
+
+} // namespace OVR
+
+#endif
diff --git a/LibOVR/Src/OVR_SensorImpl.cpp b/LibOVR/Src/OVR_SensorImpl.cpp
index fb322df..ced6541 100644
--- a/LibOVR/Src/OVR_SensorImpl.cpp
+++ b/LibOVR/Src/OVR_SensorImpl.cpp
@@ -1,882 +1,882 @@
-/************************************************************************************
-
-Filename : OVR_SensorImpl.cpp
-Content : Oculus Sensor device implementation.
-Created : March 7, 2013
-Authors : Lee Cooper
-
-Copyright : Copyright 2013 Oculus VR, Inc. All Rights reserved.
-
-Use of this software is subject to the terms of the Oculus license
-agreement provided at the time of installation or download, or which
-otherwise accompanies this software in either electronic or hard copy form.
-
-*************************************************************************************/
-
-#include "OVR_SensorImpl.h"
-
-// HMDDeviceDesc can be created/updated through Sensor carrying DisplayInfo.
-
-#include "Kernel/OVR_Timer.h"
-
-namespace OVR {
-
-//-------------------------------------------------------------------------------------
-// ***** Oculus Sensor-specific packet data structures
-
-enum {
- Sensor_VendorId = Oculus_VendorId,
- Sensor_ProductId = 0x0001,
-
- // ST's VID used originally; should be removed in the future
- Sensor_OldVendorId = 0x0483,
- Sensor_OldProductId = 0x5750,
-
- Sensor_DefaultReportRate = 500, // Hz
- Sensor_MaxReportRate = 1000 // Hz
-};
-
-// Reported data is little-endian now
-static UInt16 DecodeUInt16(const UByte* buffer)
-{
- return (UInt16(buffer[1]) << 8) | UInt16(buffer[0]);
-}
-
-static SInt16 DecodeSInt16(const UByte* buffer)
-{
- return (SInt16(buffer[1]) << 8) | SInt16(buffer[0]);
-}
-
-static UInt32 DecodeUInt32(const UByte* buffer)
-{
- return (buffer[0]) | UInt32(buffer[1] << 8) | UInt32(buffer[2] << 16) | UInt32(buffer[3] << 24);
-}
-
-static float DecodeFloat(const UByte* buffer)
-{
- union {
- UInt32 U;
- float F;
- };
-
- U = DecodeUInt32(buffer);
- return F;
-}
-
-
-static void UnpackSensor(const UByte* buffer, SInt32* x, SInt32* y, SInt32* z)
-{
- // Sign extending trick
- // from http://graphics.stanford.edu/~seander/bithacks.html#FixedSignExtend
- struct {SInt32 x:21;} s;
-
- *x = s.x = (buffer[0] << 13) | (buffer[1] << 5) | ((buffer[2] & 0xF8) >> 3);
- *y = s.x = ((buffer[2] & 0x07) << 18) | (buffer[3] << 10) | (buffer[4] << 2) |
- ((buffer[5] & 0xC0) >> 6);
- *z = s.x = ((buffer[5] & 0x3F) << 15) | (buffer[6] << 7) | (buffer[7] >> 1);
-}
-
-// Messages we care for
-enum TrackerMessageType
-{
- TrackerMessage_None = 0,
- TrackerMessage_Sensors = 1,
- TrackerMessage_Unknown = 0x100,
- TrackerMessage_SizeError = 0x101,
-};
-
-struct TrackerSample
-{
- SInt32 AccelX, AccelY, AccelZ;
- SInt32 GyroX, GyroY, GyroZ;
-};
-
-
-struct TrackerSensors
-{
- UByte SampleCount;
- UInt16 Timestamp;
- UInt16 LastCommandID;
- SInt16 Temperature;
-
- TrackerSample Samples[3];
-
- SInt16 MagX, MagY, MagZ;
-
- TrackerMessageType Decode(const UByte* buffer, int size)
- {
- if (size < 62)
- return TrackerMessage_SizeError;
-
- SampleCount = buffer[1];
- Timestamp = DecodeUInt16(buffer + 2);
- LastCommandID = DecodeUInt16(buffer + 4);
- Temperature = DecodeSInt16(buffer + 6);
-
- //if (SampleCount > 2)
- // OVR_DEBUG_LOG_TEXT(("TackerSensor::Decode SampleCount=%d\n", SampleCount));
-
- // Only unpack as many samples as there actually are
- UByte iterationCount = (SampleCount > 2) ? 3 : SampleCount;
-
- for (UByte i = 0; i < iterationCount; i++)
- {
- UnpackSensor(buffer + 8 + 16 * i, &Samples[i].AccelX, &Samples[i].AccelY, &Samples[i].AccelZ);
- UnpackSensor(buffer + 16 + 16 * i, &Samples[i].GyroX, &Samples[i].GyroY, &Samples[i].GyroZ);
- }
-
- MagX = DecodeSInt16(buffer + 56);
- MagY = DecodeSInt16(buffer + 58);
- MagZ = DecodeSInt16(buffer + 60);
-
- return TrackerMessage_Sensors;
- }
-};
-
-struct TrackerMessage
-{
- TrackerMessageType Type;
- TrackerSensors Sensors;
-};
-
-bool DecodeTrackerMessage(TrackerMessage* message, UByte* buffer, int size)
-{
- memset(message, 0, sizeof(TrackerMessage));
-
- if (size < 4)
- {
- message->Type = TrackerMessage_SizeError;
- return false;
- }
-
- switch (buffer[0])
- {
- case TrackerMessage_Sensors:
- message->Type = message->Sensors.Decode(buffer, size);
- break;
-
- default:
- message->Type = TrackerMessage_Unknown;
- break;
- }
-
- return (message->Type < TrackerMessage_Unknown) && (message->Type != TrackerMessage_None);
-}
-
-
-// ***** SensorRangeImpl Implementation
-
-// Sensor HW only accepts specific maximum range values, used to maximize
-// the 16-bit sensor outputs. Use these ramps to specify and report appropriate values.
-static const UInt16 AccelRangeRamp[] = { 2, 4, 8, 16 };
-static const UInt16 GyroRangeRamp[] = { 250, 500, 1000, 2000 };
-static const UInt16 MagRangeRamp[] = { 880, 1300, 1900, 2500 };
-
-static UInt16 SelectSensorRampValue(const UInt16* ramp, unsigned count,
- float val, float factor, const char* label)
-{
- UInt16 threshold = (UInt16)(val * factor);
-
- for (unsigned i = 0; i<count; i++)
- {
- if (ramp[i] >= threshold)
- return ramp[i];
- }
- OVR_DEBUG_LOG(("SensorDevice::SetRange - %s clamped to %0.4f",
- label, float(ramp[count-1]) / factor));
- OVR_UNUSED2(factor, label);
- return ramp[count-1];
-}
-
-// SensorScaleImpl provides buffer packing logic for the Sensor Range
-// record that can be applied to DK1 sensor through Get/SetFeature. We expose this
-// through SensorRange class, which has different units.
-struct SensorRangeImpl
-{
- enum { PacketSize = 8 };
- UByte Buffer[PacketSize];
-
- UInt16 CommandId;
- UInt16 AccelScale;
- UInt16 GyroScale;
- UInt16 MagScale;
-
- SensorRangeImpl(const SensorRange& r, UInt16 commandId = 0)
- {
- SetSensorRange(r, commandId);
- }
-
- void SetSensorRange(const SensorRange& r, UInt16 commandId = 0)
- {
- CommandId = commandId;
- AccelScale = SelectSensorRampValue(AccelRangeRamp, sizeof(AccelRangeRamp)/sizeof(AccelRangeRamp[0]),
- r.MaxAcceleration, (1.0f / 9.81f), "MaxAcceleration");
- GyroScale = SelectSensorRampValue(GyroRangeRamp, sizeof(GyroRangeRamp)/sizeof(GyroRangeRamp[0]),
- r.MaxRotationRate, Math<float>::RadToDegreeFactor, "MaxRotationRate");
- MagScale = SelectSensorRampValue(MagRangeRamp, sizeof(MagRangeRamp)/sizeof(MagRangeRamp[0]),
- r.MaxMagneticField, 1000.0f, "MaxMagneticField");
- Pack();
- }
-
- void GetSensorRange(SensorRange* r)
- {
- r->MaxAcceleration = AccelScale * 9.81f;
- r->MaxRotationRate = DegreeToRad((float)GyroScale);
- r->MaxMagneticField= MagScale * 0.001f;
- }
-
- static SensorRange GetMaxSensorRange()
- {
- return SensorRange(AccelRangeRamp[sizeof(AccelRangeRamp)/sizeof(AccelRangeRamp[0]) - 1] * 9.81f,
- GyroRangeRamp[sizeof(GyroRangeRamp)/sizeof(GyroRangeRamp[0]) - 1] *
- Math<float>::DegreeToRadFactor,
- MagRangeRamp[sizeof(MagRangeRamp)/sizeof(MagRangeRamp[0]) - 1] * 0.001f);
- }
-
- void Pack()
- {
- Buffer[0] = 4;
- Buffer[1] = UByte(CommandId & 0xFF);
- Buffer[2] = UByte(CommandId >> 8);
- Buffer[3] = UByte(AccelScale);
- Buffer[4] = UByte(GyroScale & 0xFF);
- Buffer[5] = UByte(GyroScale >> 8);
- Buffer[6] = UByte(MagScale & 0xFF);
- Buffer[7] = UByte(MagScale >> 8);
- }
-
- void Unpack()
- {
- CommandId = Buffer[1] | (UInt16(Buffer[2]) << 8);
- AccelScale= Buffer[3];
- GyroScale = Buffer[4] | (UInt16(Buffer[5]) << 8);
- MagScale = Buffer[6] | (UInt16(Buffer[7]) << 8);
- }
-};
-
-
-// Sensor configuration command, ReportId == 2.
-
-struct SensorConfigImpl
-{
- enum { PacketSize = 7 };
- UByte Buffer[PacketSize];
-
- // Flag values for Flags.
- enum {
- Flag_RawMode = 0x01,
- Flag_CallibrationTest = 0x02, // Internal test mode
- Flag_UseCallibration = 0x04,
- Flag_AutoCallibration = 0x08,
- Flag_MotionKeepAlive = 0x10,
- Flag_CommandKeepAlive = 0x20,
- Flag_SensorCoordinates = 0x40
- };
-
- UInt16 CommandId;
- UByte Flags;
- UInt16 PacketInterval;
- UInt16 KeepAliveIntervalMs;
-
- SensorConfigImpl() : CommandId(0), Flags(0), PacketInterval(0), KeepAliveIntervalMs(0)
- {
- memset(Buffer, 0, PacketSize);
- Buffer[0] = 2;
- }
-
- void SetSensorCoordinates(bool sensorCoordinates)
- { Flags = (Flags & ~Flag_SensorCoordinates) | (sensorCoordinates ? Flag_SensorCoordinates : 0); }
- bool IsUsingSensorCoordinates() const
- { return (Flags & Flag_SensorCoordinates) != 0; }
-
- void Pack()
- {
- Buffer[0] = 2;
- Buffer[1] = UByte(CommandId & 0xFF);
- Buffer[2] = UByte(CommandId >> 8);
- Buffer[3] = Flags;
- Buffer[4] = UByte(PacketInterval);
- Buffer[5] = UByte(KeepAliveIntervalMs & 0xFF);
- Buffer[6] = UByte(KeepAliveIntervalMs >> 8);
- }
-
- void Unpack()
- {
- CommandId = Buffer[1] | (UInt16(Buffer[2]) << 8);
- Flags = Buffer[3];
- PacketInterval = Buffer[4];
- KeepAliveIntervalMs= Buffer[5] | (UInt16(Buffer[6]) << 8);
- }
-
-};
-
-
-// SensorKeepAlive - feature report that needs to be sent at regular intervals for sensor
-// to receive commands.
-struct SensorKeepAliveImpl
-{
- enum { PacketSize = 5 };
- UByte Buffer[PacketSize];
-
- UInt16 CommandId;
- UInt16 KeepAliveIntervalMs;
-
- SensorKeepAliveImpl(UInt16 interval = 0, UInt16 commandId = 0)
- : CommandId(commandId), KeepAliveIntervalMs(interval)
- {
- Pack();
- }
-
- void Pack()
- {
- Buffer[0] = 8;
- Buffer[1] = UByte(CommandId & 0xFF);
- Buffer[2] = UByte(CommandId >> 8);
- Buffer[3] = UByte(KeepAliveIntervalMs & 0xFF);
- Buffer[4] = UByte(KeepAliveIntervalMs >> 8);
- }
-
- void Unpack()
- {
- CommandId = Buffer[1] | (UInt16(Buffer[2]) << 8);
- KeepAliveIntervalMs= Buffer[3] | (UInt16(Buffer[4]) << 8);
- }
-};
-
-
-//-------------------------------------------------------------------------------------
-// ***** SensorDisplayInfoImpl
-SensorDisplayInfoImpl::SensorDisplayInfoImpl()
- : CommandId(0), DistortionType(Base_None)
-{
- memset(Buffer, 0, PacketSize);
- Buffer[0] = 9;
-}
-
-void SensorDisplayInfoImpl::Unpack()
-{
- CommandId = Buffer[1] | (UInt16(Buffer[2]) << 8);
- DistortionType = Buffer[3];
- HResolution = DecodeUInt16(Buffer+4);
- VResolution = DecodeUInt16(Buffer+6);
- HScreenSize = DecodeUInt32(Buffer+8) * (1/1000000.f);
- VScreenSize = DecodeUInt32(Buffer+12) * (1/1000000.f);
- VCenter = DecodeUInt32(Buffer+16) * (1/1000000.f);
- LensSeparation = DecodeUInt32(Buffer+20) * (1/1000000.f);
- EyeToScreenDistance[0] = DecodeUInt32(Buffer+24) * (1/1000000.f);
- EyeToScreenDistance[1] = DecodeUInt32(Buffer+28) * (1/1000000.f);
- DistortionK[0] = DecodeFloat(Buffer+32);
- DistortionK[1] = DecodeFloat(Buffer+36);
- DistortionK[2] = DecodeFloat(Buffer+40);
- DistortionK[3] = DecodeFloat(Buffer+44);
- DistortionK[4] = DecodeFloat(Buffer+48);
- DistortionK[5] = DecodeFloat(Buffer+52);
-}
-
-
-//-------------------------------------------------------------------------------------
-// ***** SensorDeviceFactory
-
-SensorDeviceFactory SensorDeviceFactory::Instance;
-
-void SensorDeviceFactory::EnumerateDevices(EnumerateVisitor& visitor)
-{
-
- class SensorEnumerator : public HIDEnumerateVisitor
- {
- // Assign not supported; suppress MSVC warning.
- void operator = (const SensorEnumerator&) { }
-
- DeviceFactory* pFactory;
- EnumerateVisitor& ExternalVisitor;
- public:
- SensorEnumerator(DeviceFactory* factory, EnumerateVisitor& externalVisitor)
- : pFactory(factory), ExternalVisitor(externalVisitor) { }
-
- virtual bool MatchVendorProduct(UInt16 vendorId, UInt16 productId)
- {
- return pFactory->MatchVendorProduct(vendorId, productId);
- }
-
- virtual void Visit(HIDDevice& device, const HIDDeviceDesc& desc)
- {
- SensorDeviceCreateDesc createDesc(pFactory, desc);
- ExternalVisitor.Visit(createDesc);
-
- // Check if the sensor returns DisplayInfo. If so, try to use it to override potentially
- // mismatching monitor information (in case wrong EDID is reported by splitter),
- // or to create a new "virtualized" HMD Device.
-
- SensorDisplayInfoImpl displayInfo;
-
- if (device.GetFeatureReport(displayInfo.Buffer, SensorDisplayInfoImpl::PacketSize))
- {
- displayInfo.Unpack();
-
- // If we got display info, try to match / create HMDDevice as well
- // so that sensor settings give preference.
- if (displayInfo.DistortionType & SensorDisplayInfoImpl::Mask_BaseFmt)
- {
- SensorDeviceImpl::EnumerateHMDFromSensorDisplayInfo(displayInfo, ExternalVisitor);
- }
- }
- }
- };
-
- //double start = Timer::GetProfileSeconds();
-
- SensorEnumerator sensorEnumerator(this, visitor);
- GetManagerImpl()->GetHIDDeviceManager()->Enumerate(&sensorEnumerator);
-
- //double totalSeconds = Timer::GetProfileSeconds() - start;
-}
-
-bool SensorDeviceFactory::MatchVendorProduct(UInt16 vendorId, UInt16 productId) const
-{
- return ((vendorId == Sensor_VendorId) && (productId == Sensor_ProductId)) ||
- ((vendorId == Sensor_OldVendorId) && (productId == Sensor_OldProductId));
-}
-
-bool SensorDeviceFactory::DetectHIDDevice(DeviceManager* pdevMgr, const HIDDeviceDesc& desc)
-{
- if (MatchVendorProduct(desc.VendorId, desc.ProductId))
- {
- SensorDeviceCreateDesc createDesc(this, desc);
- return pdevMgr->AddDevice_NeedsLock(createDesc).GetPtr() != NULL;
- }
- return false;
-}
-
-//-------------------------------------------------------------------------------------
-// ***** SensorDeviceCreateDesc
-
-DeviceBase* SensorDeviceCreateDesc::NewDeviceInstance()
-{
- return new SensorDeviceImpl(this);
-}
-
-bool SensorDeviceCreateDesc::GetDeviceInfo(DeviceInfo* info) const
-{
- if ((info->InfoClassType != Device_Sensor) &&
- (info->InfoClassType != Device_None))
- return false;
-
- OVR_strcpy(info->ProductName, DeviceInfo::MaxNameLength, HIDDesc.Product.ToCStr());
- OVR_strcpy(info->Manufacturer, DeviceInfo::MaxNameLength, HIDDesc.Manufacturer.ToCStr());
- info->Type = Device_Sensor;
- info->Version = 0;
-
- if (info->InfoClassType == Device_Sensor)
- {
- SensorInfo* sinfo = (SensorInfo*)info;
- sinfo->VendorId = HIDDesc.VendorId;
- sinfo->ProductId = HIDDesc.ProductId;
- sinfo->MaxRanges = SensorRangeImpl::GetMaxSensorRange();
- OVR_strcpy(sinfo->SerialNumber, sizeof(sinfo->SerialNumber),HIDDesc.SerialNumber.ToCStr());
- }
- return true;
-}
-
-
-//-------------------------------------------------------------------------------------
-// ***** SensorDevice
-
-SensorDeviceImpl::SensorDeviceImpl(SensorDeviceCreateDesc* createDesc)
- : OVR::HIDDeviceImpl<OVR::SensorDevice>(createDesc, 0),
- Coordinates(SensorDevice::Coord_Sensor),
- HWCoordinates(SensorDevice::Coord_HMD), // HW reports HMD coordinates by default.
- NextKeepAliveTicks(0),
- MaxValidRange(SensorRangeImpl::GetMaxSensorRange())
-{
- SequenceValid = false;
- LastSampleCount= 0;
- LastTimestamp = 0;
-
- OldCommandId = 0;
-}
-
-SensorDeviceImpl::~SensorDeviceImpl()
-{
- // Check that Shutdown() was called.
- OVR_ASSERT(!pCreateDesc->pDevice);
-}
-
-// Internal creation APIs.
-bool SensorDeviceImpl::Initialize(DeviceBase* parent)
-{
- if (HIDDeviceImpl<OVR::SensorDevice>::Initialize(parent))
- {
- openDevice();
-
- LogText("OVR::SensorDevice initialized.\n");
-
- return true;
- }
-
- return false;
-}
-
-void SensorDeviceImpl::openDevice()
-{
-
- // Read the currently configured range from sensor.
- SensorRangeImpl sr(SensorRange(), 0);
-
- if (GetInternalDevice()->GetFeatureReport(sr.Buffer, SensorRangeImpl::PacketSize))
- {
- sr.Unpack();
- sr.GetSensorRange(&CurrentRange);
- }
-
-
- // If the sensor has "DisplayInfo" data, use HMD coordinate frame by default.
- SensorDisplayInfoImpl displayInfo;
- if (GetInternalDevice()->GetFeatureReport(displayInfo.Buffer, SensorDisplayInfoImpl::PacketSize))
- {
- displayInfo.Unpack();
- Coordinates = (displayInfo.DistortionType & SensorDisplayInfoImpl::Mask_BaseFmt) ?
- Coord_HMD : Coord_Sensor;
- }
-
- // Read/Apply sensor config.
- setCoordinateFrame(Coordinates);
- setReportRate(Sensor_DefaultReportRate);
-
- // Set Keep-alive at 10 seconds.
- SensorKeepAliveImpl skeepAlive(10 * 1000);
- GetInternalDevice()->SetFeatureReport(skeepAlive.Buffer, SensorKeepAliveImpl::PacketSize);
-}
-
-void SensorDeviceImpl::closeDeviceOnError()
-{
- LogText("OVR::SensorDevice - Lost connection to '%s'\n", getHIDDesc()->Path.ToCStr());
- NextKeepAliveTicks = 0;
-}
-
-void SensorDeviceImpl::Shutdown()
-{
- HIDDeviceImpl<OVR::SensorDevice>::Shutdown();
-
- LogText("OVR::SensorDevice - Closed '%s'\n", getHIDDesc()->Path.ToCStr());
-}
-
-
-void SensorDeviceImpl::OnInputReport(UByte* pData, UInt32 length)
-{
-
- bool processed = false;
- if (!processed)
- {
-
- TrackerMessage message;
- if (DecodeTrackerMessage(&message, pData, length))
- {
- processed = true;
- onTrackerMessage(&message);
- }
- }
-}
-
-UInt64 SensorDeviceImpl::OnTicks(UInt64 ticksMks)
-{
-
- if (ticksMks >= NextKeepAliveTicks)
- {
- // Use 3-seconds keep alive by default.
- UInt64 keepAliveDelta = Timer::MksPerSecond * 3;
-
- // Set Keep-alive at 10 seconds.
- SensorKeepAliveImpl skeepAlive(10 * 1000);
- // OnTicks is called from background thread so we don't need to add this to the command queue.
- GetInternalDevice()->SetFeatureReport(skeepAlive.Buffer, SensorKeepAliveImpl::PacketSize);
-
- // Emit keep-alive every few seconds.
- NextKeepAliveTicks = ticksMks + keepAliveDelta;
- }
- return NextKeepAliveTicks - ticksMks;
-}
-
-bool SensorDeviceImpl::SetRange(const SensorRange& range, bool waitFlag)
-{
- bool result = 0;
- ThreadCommandQueue * threadQueue = GetManagerImpl()->GetThreadQueue();
-
- if (!waitFlag)
- {
- return threadQueue->PushCall(this, &SensorDeviceImpl::setRange, range);
- }
-
- if (!threadQueue->PushCallAndWaitResult(this,
- &SensorDeviceImpl::setRange,
- &result,
- range))
- {
- return false;
- }
-
- return result;
-}
-
-void SensorDeviceImpl::GetRange(SensorRange* range) const
-{
- Lock::Locker lockScope(GetLock());
- *range = CurrentRange;
-}
-
-bool SensorDeviceImpl::setRange(const SensorRange& range)
-{
- SensorRangeImpl sr(range);
-
- if (GetInternalDevice()->SetFeatureReport(sr.Buffer, SensorRangeImpl::PacketSize))
- {
- Lock::Locker lockScope(GetLock());
- sr.GetSensorRange(&CurrentRange);
- return true;
- }
-
- return false;
-}
-
-void SensorDeviceImpl::SetCoordinateFrame(CoordinateFrame coordframe)
-{
- // Push call with wait.
- GetManagerImpl()->GetThreadQueue()->
- PushCall(this, &SensorDeviceImpl::setCoordinateFrame, coordframe, true);
-}
-
-SensorDevice::CoordinateFrame SensorDeviceImpl::GetCoordinateFrame() const
-{
- return Coordinates;
-}
-
-Void SensorDeviceImpl::setCoordinateFrame(CoordinateFrame coordframe)
-{
-
- Coordinates = coordframe;
-
- // Read the original coordinate frame, then try to change it.
- SensorConfigImpl scfg;
- if (GetInternalDevice()->GetFeatureReport(scfg.Buffer, SensorConfigImpl::PacketSize))
- {
- scfg.Unpack();
- }
-
- scfg.SetSensorCoordinates(coordframe == Coord_Sensor);
- scfg.Pack();
-
- GetInternalDevice()->SetFeatureReport(scfg.Buffer, SensorConfigImpl::PacketSize);
-
- // Re-read the state, in case of older firmware that doesn't support Sensor coordinates.
- if (GetInternalDevice()->GetFeatureReport(scfg.Buffer, SensorConfigImpl::PacketSize))
- {
- scfg.Unpack();
- HWCoordinates = scfg.IsUsingSensorCoordinates() ? Coord_Sensor : Coord_HMD;
- }
- else
- {
- HWCoordinates = Coord_HMD;
- }
- return 0;
-}
-
-void SensorDeviceImpl::SetReportRate(unsigned rateHz)
-{
- // Push call with wait.
- GetManagerImpl()->GetThreadQueue()->
- PushCall(this, &SensorDeviceImpl::setReportRate, rateHz, true);
-}
-
-unsigned SensorDeviceImpl::GetReportRate() const
-{
- // Read the original configuration
- SensorConfigImpl scfg;
- if (GetInternalDevice()->GetFeatureReport(scfg.Buffer, SensorConfigImpl::PacketSize))
- {
- scfg.Unpack();
- return Sensor_MaxReportRate / (scfg.PacketInterval + 1);
- }
- return 0; // error
-}
-
-Void SensorDeviceImpl::setReportRate(unsigned rateHz)
-{
- // Read the original configuration
- SensorConfigImpl scfg;
- if (GetInternalDevice()->GetFeatureReport(scfg.Buffer, SensorConfigImpl::PacketSize))
- {
- scfg.Unpack();
- }
-
- if (rateHz > Sensor_MaxReportRate)
- rateHz = Sensor_MaxReportRate;
- else if (rateHz == 0)
- rateHz = Sensor_DefaultReportRate;
-
- scfg.PacketInterval = UInt16((Sensor_MaxReportRate / rateHz) - 1);
-
- scfg.Pack();
-
- GetInternalDevice()->SetFeatureReport(scfg.Buffer, SensorConfigImpl::PacketSize);
- return 0;
-}
-
-void SensorDeviceImpl::SetMessageHandler(MessageHandler* handler)
-{
- if (handler)
- {
- SequenceValid = false;
- DeviceBase::SetMessageHandler(handler);
- }
- else
- {
- DeviceBase::SetMessageHandler(handler);
- }
-}
-
-// Sensor reports data in the following coordinate system:
-// Accelerometer: 10^-4 m/s^2; X forward, Y right, Z Down.
-// Gyro: 10^-4 rad/s; X positive roll right, Y positive pitch up; Z positive yaw right.
-
-
-// We need to convert it to the following RHS coordinate system:
-// X right, Y Up, Z Back (out of screen)
-//
-Vector3f AccelFromBodyFrameUpdate(const TrackerSensors& update, UByte sampleNumber,
- bool convertHMDToSensor = false)
-{
- const TrackerSample& sample = update.Samples[sampleNumber];
- float ax = (float)sample.AccelX;
- float ay = (float)sample.AccelY;
- float az = (float)sample.AccelZ;
-
- Vector3f val = convertHMDToSensor ? Vector3f(ax, az, -ay) : Vector3f(ax, ay, az);
- return val * 0.0001f;
-}
-
-
-Vector3f MagFromBodyFrameUpdate(const TrackerSensors& update,
- bool convertHMDToSensor = false)
-{
- // Note: Y and Z are swapped in comparison to the Accel.
- // This accounts for DK1 sensor firmware axis swap, which should be undone in future releases.
- if (!convertHMDToSensor)
- {
- return Vector3f( (float)update.MagX,
- (float)update.MagZ,
- (float)update.MagY) * 0.0001f;
- }
-
- return Vector3f( (float)update.MagX,
- (float)update.MagY,
- -(float)update.MagZ) * 0.0001f;
-}
-
-Vector3f EulerFromBodyFrameUpdate(const TrackerSensors& update, UByte sampleNumber,
- bool convertHMDToSensor = false)
-{
- const TrackerSample& sample = update.Samples[sampleNumber];
- float gx = (float)sample.GyroX;
- float gy = (float)sample.GyroY;
- float gz = (float)sample.GyroZ;
-
- Vector3f val = convertHMDToSensor ? Vector3f(gx, gz, -gy) : Vector3f(gx, gy, gz);
- return val * 0.0001f;
-}
-
-
-void SensorDeviceImpl::onTrackerMessage(TrackerMessage* message)
-{
- if (message->Type != TrackerMessage_Sensors)
- return;
-
- const float timeUnit = (1.0f / 1000.f);
- TrackerSensors& s = message->Sensors;
-
-
- // Call OnMessage() within a lock to avoid conflicts with handlers.
- Lock::Locker scopeLock(HandlerRef.GetLock());
-
-
- if (SequenceValid)
- {
- unsigned timestampDelta;
-
- if (s.Timestamp < LastTimestamp)
- timestampDelta = ((((int)s.Timestamp) + 0x10000) - (int)LastTimestamp);
- else
- timestampDelta = (s.Timestamp - LastTimestamp);
-
- // If we missed a small number of samples, replicate the last sample.
- if ((timestampDelta > LastSampleCount) && (timestampDelta <= 254))
- {
- if (HandlerRef.GetHandler())
- {
- MessageBodyFrame sensors(this);
- sensors.TimeDelta = (timestampDelta - LastSampleCount) * timeUnit;
- sensors.Acceleration = LastAcceleration;
- sensors.RotationRate = LastRotationRate;
- sensors.MagneticField = LastMagneticField;
- sensors.Temperature = LastTemperature;
-
- HandlerRef.GetHandler()->OnMessage(sensors);
- }
- }
- }
- else
- {
- LastAcceleration = Vector3f(0);
- LastRotationRate = Vector3f(0);
- LastMagneticField= Vector3f(0);
- LastTemperature = 0;
- SequenceValid = true;
- }
-
- LastSampleCount = s.SampleCount;
- LastTimestamp = s.Timestamp;
-
- bool convertHMDToSensor = (Coordinates == Coord_Sensor) && (HWCoordinates == Coord_HMD);
-
- if (HandlerRef.GetHandler())
- {
- MessageBodyFrame sensors(this);
- UByte iterations = s.SampleCount;
-
- if (s.SampleCount > 3)
- {
- iterations = 3;
- sensors.TimeDelta = (s.SampleCount - 2) * timeUnit;
- }
- else
- {
- sensors.TimeDelta = timeUnit;
- }
-
- for (UByte i = 0; i < iterations; i++)
- {
- sensors.Acceleration = AccelFromBodyFrameUpdate(s, i, convertHMDToSensor);
- sensors.RotationRate = EulerFromBodyFrameUpdate(s, i, convertHMDToSensor);
- sensors.MagneticField= MagFromBodyFrameUpdate(s, convertHMDToSensor);
- sensors.Temperature = s.Temperature * 0.01f;
- HandlerRef.GetHandler()->OnMessage(sensors);
- // TimeDelta for the last two sample is always fixed.
- sensors.TimeDelta = timeUnit;
- }
-
- LastAcceleration = sensors.Acceleration;
- LastRotationRate = sensors.RotationRate;
- LastMagneticField= sensors.MagneticField;
- LastTemperature = sensors.Temperature;
- }
- else
- {
- UByte i = (s.SampleCount > 3) ? 2 : (s.SampleCount - 1);
- LastAcceleration = AccelFromBodyFrameUpdate(s, i, convertHMDToSensor);
- LastRotationRate = EulerFromBodyFrameUpdate(s, i, convertHMDToSensor);
- LastMagneticField = MagFromBodyFrameUpdate(s, convertHMDToSensor);
- LastTemperature = s.Temperature * 0.01f;
- }
-}
-
-} // namespace OVR
-
-
+/************************************************************************************
+
+Filename : OVR_SensorImpl.cpp
+Content : Oculus Sensor device implementation.
+Created : March 7, 2013
+Authors : Lee Cooper
+
+Copyright : Copyright 2013 Oculus VR, Inc. All Rights reserved.
+
+Use of this software is subject to the terms of the Oculus license
+agreement provided at the time of installation or download, or which
+otherwise accompanies this software in either electronic or hard copy form.
+
+*************************************************************************************/
+
+#include "OVR_SensorImpl.h"
+
+// HMDDeviceDesc can be created/updated through Sensor carrying DisplayInfo.
+
+#include "Kernel/OVR_Timer.h"
+
+namespace OVR {
+
+//-------------------------------------------------------------------------------------
+// ***** Oculus Sensor-specific packet data structures
+
+enum {
+ Sensor_VendorId = Oculus_VendorId,
+ Sensor_ProductId = 0x0001,
+
+ // ST's VID used originally; should be removed in the future
+ Sensor_OldVendorId = 0x0483,
+ Sensor_OldProductId = 0x5750,
+
+ Sensor_DefaultReportRate = 500, // Hz
+ Sensor_MaxReportRate = 1000 // Hz
+};
+
+// Reported data is little-endian now
+static UInt16 DecodeUInt16(const UByte* buffer)
+{
+ return (UInt16(buffer[1]) << 8) | UInt16(buffer[0]);
+}
+
+static SInt16 DecodeSInt16(const UByte* buffer)
+{
+ return (SInt16(buffer[1]) << 8) | SInt16(buffer[0]);
+}
+
+static UInt32 DecodeUInt32(const UByte* buffer)
+{
+ return (buffer[0]) | UInt32(buffer[1] << 8) | UInt32(buffer[2] << 16) | UInt32(buffer[3] << 24);
+}
+
+static float DecodeFloat(const UByte* buffer)
+{
+ union {
+ UInt32 U;
+ float F;
+ };
+
+ U = DecodeUInt32(buffer);
+ return F;
+}
+
+
+static void UnpackSensor(const UByte* buffer, SInt32* x, SInt32* y, SInt32* z)
+{
+ // Sign extending trick
+ // from http://graphics.stanford.edu/~seander/bithacks.html#FixedSignExtend
+ struct {SInt32 x:21;} s;
+
+ *x = s.x = (buffer[0] << 13) | (buffer[1] << 5) | ((buffer[2] & 0xF8) >> 3);
+ *y = s.x = ((buffer[2] & 0x07) << 18) | (buffer[3] << 10) | (buffer[4] << 2) |
+ ((buffer[5] & 0xC0) >> 6);
+ *z = s.x = ((buffer[5] & 0x3F) << 15) | (buffer[6] << 7) | (buffer[7] >> 1);
+}
+
+// Messages we care for
+enum TrackerMessageType
+{
+ TrackerMessage_None = 0,
+ TrackerMessage_Sensors = 1,
+ TrackerMessage_Unknown = 0x100,
+ TrackerMessage_SizeError = 0x101,
+};
+
+struct TrackerSample
+{
+ SInt32 AccelX, AccelY, AccelZ;
+ SInt32 GyroX, GyroY, GyroZ;
+};
+
+
+struct TrackerSensors
+{
+ UByte SampleCount;
+ UInt16 Timestamp;
+ UInt16 LastCommandID;
+ SInt16 Temperature;
+
+ TrackerSample Samples[3];
+
+ SInt16 MagX, MagY, MagZ;
+
+ TrackerMessageType Decode(const UByte* buffer, int size)
+ {
+ if (size < 62)
+ return TrackerMessage_SizeError;
+
+ SampleCount = buffer[1];
+ Timestamp = DecodeUInt16(buffer + 2);
+ LastCommandID = DecodeUInt16(buffer + 4);
+ Temperature = DecodeSInt16(buffer + 6);
+
+ //if (SampleCount > 2)
+ // OVR_DEBUG_LOG_TEXT(("TackerSensor::Decode SampleCount=%d\n", SampleCount));
+
+ // Only unpack as many samples as there actually are
+ UByte iterationCount = (SampleCount > 2) ? 3 : SampleCount;
+
+ for (UByte i = 0; i < iterationCount; i++)
+ {
+ UnpackSensor(buffer + 8 + 16 * i, &Samples[i].AccelX, &Samples[i].AccelY, &Samples[i].AccelZ);
+ UnpackSensor(buffer + 16 + 16 * i, &Samples[i].GyroX, &Samples[i].GyroY, &Samples[i].GyroZ);
+ }
+
+ MagX = DecodeSInt16(buffer + 56);
+ MagY = DecodeSInt16(buffer + 58);
+ MagZ = DecodeSInt16(buffer + 60);
+
+ return TrackerMessage_Sensors;
+ }
+};
+
+struct TrackerMessage
+{
+ TrackerMessageType Type;
+ TrackerSensors Sensors;
+};
+
+bool DecodeTrackerMessage(TrackerMessage* message, UByte* buffer, int size)
+{
+ memset(message, 0, sizeof(TrackerMessage));
+
+ if (size < 4)
+ {
+ message->Type = TrackerMessage_SizeError;
+ return false;
+ }
+
+ switch (buffer[0])
+ {
+ case TrackerMessage_Sensors:
+ message->Type = message->Sensors.Decode(buffer, size);
+ break;
+
+ default:
+ message->Type = TrackerMessage_Unknown;
+ break;
+ }
+
+ return (message->Type < TrackerMessage_Unknown) && (message->Type != TrackerMessage_None);
+}
+
+
+// ***** SensorRangeImpl Implementation
+
+// Sensor HW only accepts specific maximum range values, used to maximize
+// the 16-bit sensor outputs. Use these ramps to specify and report appropriate values.
+static const UInt16 AccelRangeRamp[] = { 2, 4, 8, 16 };
+static const UInt16 GyroRangeRamp[] = { 250, 500, 1000, 2000 };
+static const UInt16 MagRangeRamp[] = { 880, 1300, 1900, 2500 };
+
+static UInt16 SelectSensorRampValue(const UInt16* ramp, unsigned count,
+ float val, float factor, const char* label)
+{
+ UInt16 threshold = (UInt16)(val * factor);
+
+ for (unsigned i = 0; i<count; i++)
+ {
+ if (ramp[i] >= threshold)
+ return ramp[i];
+ }
+ OVR_DEBUG_LOG(("SensorDevice::SetRange - %s clamped to %0.4f",
+ label, float(ramp[count-1]) / factor));
+ OVR_UNUSED2(factor, label);
+ return ramp[count-1];
+}
+
+// SensorScaleImpl provides buffer packing logic for the Sensor Range
+// record that can be applied to DK1 sensor through Get/SetFeature. We expose this
+// through SensorRange class, which has different units.
+struct SensorRangeImpl
+{
+ enum { PacketSize = 8 };
+ UByte Buffer[PacketSize];
+
+ UInt16 CommandId;
+ UInt16 AccelScale;
+ UInt16 GyroScale;
+ UInt16 MagScale;
+
+ SensorRangeImpl(const SensorRange& r, UInt16 commandId = 0)
+ {
+ SetSensorRange(r, commandId);
+ }
+
+ void SetSensorRange(const SensorRange& r, UInt16 commandId = 0)
+ {
+ CommandId = commandId;
+ AccelScale = SelectSensorRampValue(AccelRangeRamp, sizeof(AccelRangeRamp)/sizeof(AccelRangeRamp[0]),
+ r.MaxAcceleration, (1.0f / 9.81f), "MaxAcceleration");
+ GyroScale = SelectSensorRampValue(GyroRangeRamp, sizeof(GyroRangeRamp)/sizeof(GyroRangeRamp[0]),
+ r.MaxRotationRate, Math<float>::RadToDegreeFactor, "MaxRotationRate");
+ MagScale = SelectSensorRampValue(MagRangeRamp, sizeof(MagRangeRamp)/sizeof(MagRangeRamp[0]),
+ r.MaxMagneticField, 1000.0f, "MaxMagneticField");
+ Pack();
+ }
+
+ void GetSensorRange(SensorRange* r)
+ {
+ r->MaxAcceleration = AccelScale * 9.81f;
+ r->MaxRotationRate = DegreeToRad((float)GyroScale);
+ r->MaxMagneticField= MagScale * 0.001f;
+ }
+
+ static SensorRange GetMaxSensorRange()
+ {
+ return SensorRange(AccelRangeRamp[sizeof(AccelRangeRamp)/sizeof(AccelRangeRamp[0]) - 1] * 9.81f,
+ GyroRangeRamp[sizeof(GyroRangeRamp)/sizeof(GyroRangeRamp[0]) - 1] *
+ Math<float>::DegreeToRadFactor,
+ MagRangeRamp[sizeof(MagRangeRamp)/sizeof(MagRangeRamp[0]) - 1] * 0.001f);
+ }
+
+ void Pack()
+ {
+ Buffer[0] = 4;
+ Buffer[1] = UByte(CommandId & 0xFF);
+ Buffer[2] = UByte(CommandId >> 8);
+ Buffer[3] = UByte(AccelScale);
+ Buffer[4] = UByte(GyroScale & 0xFF);
+ Buffer[5] = UByte(GyroScale >> 8);
+ Buffer[6] = UByte(MagScale & 0xFF);
+ Buffer[7] = UByte(MagScale >> 8);
+ }
+
+ void Unpack()
+ {
+ CommandId = Buffer[1] | (UInt16(Buffer[2]) << 8);
+ AccelScale= Buffer[3];
+ GyroScale = Buffer[4] | (UInt16(Buffer[5]) << 8);
+ MagScale = Buffer[6] | (UInt16(Buffer[7]) << 8);
+ }
+};
+
+
+// Sensor configuration command, ReportId == 2.
+
+struct SensorConfigImpl
+{
+ enum { PacketSize = 7 };
+ UByte Buffer[PacketSize];
+
+ // Flag values for Flags.
+ enum {
+ Flag_RawMode = 0x01,
+ Flag_CallibrationTest = 0x02, // Internal test mode
+ Flag_UseCallibration = 0x04,
+ Flag_AutoCallibration = 0x08,
+ Flag_MotionKeepAlive = 0x10,
+ Flag_CommandKeepAlive = 0x20,
+ Flag_SensorCoordinates = 0x40
+ };
+
+ UInt16 CommandId;
+ UByte Flags;
+ UInt16 PacketInterval;
+ UInt16 KeepAliveIntervalMs;
+
+ SensorConfigImpl() : CommandId(0), Flags(0), PacketInterval(0), KeepAliveIntervalMs(0)
+ {
+ memset(Buffer, 0, PacketSize);
+ Buffer[0] = 2;
+ }
+
+ void SetSensorCoordinates(bool sensorCoordinates)
+ { Flags = (Flags & ~Flag_SensorCoordinates) | (sensorCoordinates ? Flag_SensorCoordinates : 0); }
+ bool IsUsingSensorCoordinates() const
+ { return (Flags & Flag_SensorCoordinates) != 0; }
+
+ void Pack()
+ {
+ Buffer[0] = 2;
+ Buffer[1] = UByte(CommandId & 0xFF);
+ Buffer[2] = UByte(CommandId >> 8);
+ Buffer[3] = Flags;
+ Buffer[4] = UByte(PacketInterval);
+ Buffer[5] = UByte(KeepAliveIntervalMs & 0xFF);
+ Buffer[6] = UByte(KeepAliveIntervalMs >> 8);
+ }
+
+ void Unpack()
+ {
+ CommandId = Buffer[1] | (UInt16(Buffer[2]) << 8);
+ Flags = Buffer[3];
+ PacketInterval = Buffer[4];
+ KeepAliveIntervalMs= Buffer[5] | (UInt16(Buffer[6]) << 8);
+ }
+
+};
+
+
+// SensorKeepAlive - feature report that needs to be sent at regular intervals for sensor
+// to receive commands.
+struct SensorKeepAliveImpl
+{
+ enum { PacketSize = 5 };
+ UByte Buffer[PacketSize];
+
+ UInt16 CommandId;
+ UInt16 KeepAliveIntervalMs;
+
+ SensorKeepAliveImpl(UInt16 interval = 0, UInt16 commandId = 0)
+ : CommandId(commandId), KeepAliveIntervalMs(interval)
+ {
+ Pack();
+ }
+
+ void Pack()
+ {
+ Buffer[0] = 8;
+ Buffer[1] = UByte(CommandId & 0xFF);
+ Buffer[2] = UByte(CommandId >> 8);
+ Buffer[3] = UByte(KeepAliveIntervalMs & 0xFF);
+ Buffer[4] = UByte(KeepAliveIntervalMs >> 8);
+ }
+
+ void Unpack()
+ {
+ CommandId = Buffer[1] | (UInt16(Buffer[2]) << 8);
+ KeepAliveIntervalMs= Buffer[3] | (UInt16(Buffer[4]) << 8);
+ }
+};
+
+
+//-------------------------------------------------------------------------------------
+// ***** SensorDisplayInfoImpl
+SensorDisplayInfoImpl::SensorDisplayInfoImpl()
+ : CommandId(0), DistortionType(Base_None)
+{
+ memset(Buffer, 0, PacketSize);
+ Buffer[0] = 9;
+}
+
+void SensorDisplayInfoImpl::Unpack()
+{
+ CommandId = Buffer[1] | (UInt16(Buffer[2]) << 8);
+ DistortionType = Buffer[3];
+ HResolution = DecodeUInt16(Buffer+4);
+ VResolution = DecodeUInt16(Buffer+6);
+ HScreenSize = DecodeUInt32(Buffer+8) * (1/1000000.f);
+ VScreenSize = DecodeUInt32(Buffer+12) * (1/1000000.f);
+ VCenter = DecodeUInt32(Buffer+16) * (1/1000000.f);
+ LensSeparation = DecodeUInt32(Buffer+20) * (1/1000000.f);
+ EyeToScreenDistance[0] = DecodeUInt32(Buffer+24) * (1/1000000.f);
+ EyeToScreenDistance[1] = DecodeUInt32(Buffer+28) * (1/1000000.f);
+ DistortionK[0] = DecodeFloat(Buffer+32);
+ DistortionK[1] = DecodeFloat(Buffer+36);
+ DistortionK[2] = DecodeFloat(Buffer+40);
+ DistortionK[3] = DecodeFloat(Buffer+44);
+ DistortionK[4] = DecodeFloat(Buffer+48);
+ DistortionK[5] = DecodeFloat(Buffer+52);
+}
+
+
+//-------------------------------------------------------------------------------------
+// ***** SensorDeviceFactory
+
+SensorDeviceFactory SensorDeviceFactory::Instance;
+
+void SensorDeviceFactory::EnumerateDevices(EnumerateVisitor& visitor)
+{
+
+ class SensorEnumerator : public HIDEnumerateVisitor
+ {
+ // Assign not supported; suppress MSVC warning.
+ void operator = (const SensorEnumerator&) { }
+
+ DeviceFactory* pFactory;
+ EnumerateVisitor& ExternalVisitor;
+ public:
+ SensorEnumerator(DeviceFactory* factory, EnumerateVisitor& externalVisitor)
+ : pFactory(factory), ExternalVisitor(externalVisitor) { }
+
+ virtual bool MatchVendorProduct(UInt16 vendorId, UInt16 productId)
+ {
+ return pFactory->MatchVendorProduct(vendorId, productId);
+ }
+
+ virtual void Visit(HIDDevice& device, const HIDDeviceDesc& desc)
+ {
+ SensorDeviceCreateDesc createDesc(pFactory, desc);
+ ExternalVisitor.Visit(createDesc);
+
+ // Check if the sensor returns DisplayInfo. If so, try to use it to override potentially
+ // mismatching monitor information (in case wrong EDID is reported by splitter),
+ // or to create a new "virtualized" HMD Device.
+
+ SensorDisplayInfoImpl displayInfo;
+
+ if (device.GetFeatureReport(displayInfo.Buffer, SensorDisplayInfoImpl::PacketSize))
+ {
+ displayInfo.Unpack();
+
+ // If we got display info, try to match / create HMDDevice as well
+ // so that sensor settings give preference.
+ if (displayInfo.DistortionType & SensorDisplayInfoImpl::Mask_BaseFmt)
+ {
+ SensorDeviceImpl::EnumerateHMDFromSensorDisplayInfo(displayInfo, ExternalVisitor);
+ }
+ }
+ }
+ };
+
+ //double start = Timer::GetProfileSeconds();
+
+ SensorEnumerator sensorEnumerator(this, visitor);
+ GetManagerImpl()->GetHIDDeviceManager()->Enumerate(&sensorEnumerator);
+
+ //double totalSeconds = Timer::GetProfileSeconds() - start;
+}
+
+bool SensorDeviceFactory::MatchVendorProduct(UInt16 vendorId, UInt16 productId) const
+{
+ return ((vendorId == Sensor_VendorId) && (productId == Sensor_ProductId)) ||
+ ((vendorId == Sensor_OldVendorId) && (productId == Sensor_OldProductId));
+}
+
+bool SensorDeviceFactory::DetectHIDDevice(DeviceManager* pdevMgr, const HIDDeviceDesc& desc)
+{
+ if (MatchVendorProduct(desc.VendorId, desc.ProductId))
+ {
+ SensorDeviceCreateDesc createDesc(this, desc);
+ return pdevMgr->AddDevice_NeedsLock(createDesc).GetPtr() != NULL;
+ }
+ return false;
+}
+
+//-------------------------------------------------------------------------------------
+// ***** SensorDeviceCreateDesc
+
+DeviceBase* SensorDeviceCreateDesc::NewDeviceInstance()
+{
+ return new SensorDeviceImpl(this);
+}
+
+bool SensorDeviceCreateDesc::GetDeviceInfo(DeviceInfo* info) const
+{
+ if ((info->InfoClassType != Device_Sensor) &&
+ (info->InfoClassType != Device_None))
+ return false;
+
+ OVR_strcpy(info->ProductName, DeviceInfo::MaxNameLength, HIDDesc.Product.ToCStr());
+ OVR_strcpy(info->Manufacturer, DeviceInfo::MaxNameLength, HIDDesc.Manufacturer.ToCStr());
+ info->Type = Device_Sensor;
+ info->Version = 0;
+
+ if (info->InfoClassType == Device_Sensor)
+ {
+ SensorInfo* sinfo = (SensorInfo*)info;
+ sinfo->VendorId = HIDDesc.VendorId;
+ sinfo->ProductId = HIDDesc.ProductId;
+ sinfo->MaxRanges = SensorRangeImpl::GetMaxSensorRange();
+ OVR_strcpy(sinfo->SerialNumber, sizeof(sinfo->SerialNumber),HIDDesc.SerialNumber.ToCStr());
+ }
+ return true;
+}
+
+
+//-------------------------------------------------------------------------------------
+// ***** SensorDevice
+
+SensorDeviceImpl::SensorDeviceImpl(SensorDeviceCreateDesc* createDesc)
+ : OVR::HIDDeviceImpl<OVR::SensorDevice>(createDesc, 0),
+ Coordinates(SensorDevice::Coord_Sensor),
+ HWCoordinates(SensorDevice::Coord_HMD), // HW reports HMD coordinates by default.
+ NextKeepAliveTicks(0),
+ MaxValidRange(SensorRangeImpl::GetMaxSensorRange())
+{
+ SequenceValid = false;
+ LastSampleCount= 0;
+ LastTimestamp = 0;
+
+ OldCommandId = 0;
+}
+
+SensorDeviceImpl::~SensorDeviceImpl()
+{
+ // Check that Shutdown() was called.
+ OVR_ASSERT(!pCreateDesc->pDevice);
+}
+
+// Internal creation APIs.
+bool SensorDeviceImpl::Initialize(DeviceBase* parent)
+{
+ if (HIDDeviceImpl<OVR::SensorDevice>::Initialize(parent))
+ {
+ openDevice();
+
+ LogText("OVR::SensorDevice initialized.\n");
+
+ return true;
+ }
+
+ return false;
+}
+
+void SensorDeviceImpl::openDevice()
+{
+
+ // Read the currently configured range from sensor.
+ SensorRangeImpl sr(SensorRange(), 0);
+
+ if (GetInternalDevice()->GetFeatureReport(sr.Buffer, SensorRangeImpl::PacketSize))
+ {
+ sr.Unpack();
+ sr.GetSensorRange(&CurrentRange);
+ }
+
+
+ // If the sensor has "DisplayInfo" data, use HMD coordinate frame by default.
+ SensorDisplayInfoImpl displayInfo;
+ if (GetInternalDevice()->GetFeatureReport(displayInfo.Buffer, SensorDisplayInfoImpl::PacketSize))
+ {
+ displayInfo.Unpack();
+ Coordinates = (displayInfo.DistortionType & SensorDisplayInfoImpl::Mask_BaseFmt) ?
+ Coord_HMD : Coord_Sensor;
+ }
+
+ // Read/Apply sensor config.
+ setCoordinateFrame(Coordinates);
+ setReportRate(Sensor_DefaultReportRate);
+
+ // Set Keep-alive at 10 seconds.
+ SensorKeepAliveImpl skeepAlive(10 * 1000);
+ GetInternalDevice()->SetFeatureReport(skeepAlive.Buffer, SensorKeepAliveImpl::PacketSize);
+}
+
+void SensorDeviceImpl::closeDeviceOnError()
+{
+ LogText("OVR::SensorDevice - Lost connection to '%s'\n", getHIDDesc()->Path.ToCStr());
+ NextKeepAliveTicks = 0;
+}
+
+void SensorDeviceImpl::Shutdown()
+{
+ HIDDeviceImpl<OVR::SensorDevice>::Shutdown();
+
+ LogText("OVR::SensorDevice - Closed '%s'\n", getHIDDesc()->Path.ToCStr());
+}
+
+
+void SensorDeviceImpl::OnInputReport(UByte* pData, UInt32 length)
+{
+
+ bool processed = false;
+ if (!processed)
+ {
+
+ TrackerMessage message;
+ if (DecodeTrackerMessage(&message, pData, length))
+ {
+ processed = true;
+ onTrackerMessage(&message);
+ }
+ }
+}
+
+UInt64 SensorDeviceImpl::OnTicks(UInt64 ticksMks)
+{
+
+ if (ticksMks >= NextKeepAliveTicks)
+ {
+ // Use 3-seconds keep alive by default.
+ UInt64 keepAliveDelta = Timer::MksPerSecond * 3;
+
+ // Set Keep-alive at 10 seconds.
+ SensorKeepAliveImpl skeepAlive(10 * 1000);
+ // OnTicks is called from background thread so we don't need to add this to the command queue.
+ GetInternalDevice()->SetFeatureReport(skeepAlive.Buffer, SensorKeepAliveImpl::PacketSize);
+
+ // Emit keep-alive every few seconds.
+ NextKeepAliveTicks = ticksMks + keepAliveDelta;
+ }
+ return NextKeepAliveTicks - ticksMks;
+}
+
+bool SensorDeviceImpl::SetRange(const SensorRange& range, bool waitFlag)
+{
+ bool result = 0;
+ ThreadCommandQueue * threadQueue = GetManagerImpl()->GetThreadQueue();
+
+ if (!waitFlag)
+ {
+ return threadQueue->PushCall(this, &SensorDeviceImpl::setRange, range);
+ }
+
+ if (!threadQueue->PushCallAndWaitResult(this,
+ &SensorDeviceImpl::setRange,
+ &result,
+ range))
+ {
+ return false;
+ }
+
+ return result;
+}
+
+void SensorDeviceImpl::GetRange(SensorRange* range) const
+{
+ Lock::Locker lockScope(GetLock());
+ *range = CurrentRange;
+}
+
+bool SensorDeviceImpl::setRange(const SensorRange& range)
+{
+ SensorRangeImpl sr(range);
+
+ if (GetInternalDevice()->SetFeatureReport(sr.Buffer, SensorRangeImpl::PacketSize))
+ {
+ Lock::Locker lockScope(GetLock());
+ sr.GetSensorRange(&CurrentRange);
+ return true;
+ }
+
+ return false;
+}
+
+void SensorDeviceImpl::SetCoordinateFrame(CoordinateFrame coordframe)
+{
+ // Push call with wait.
+ GetManagerImpl()->GetThreadQueue()->
+ PushCall(this, &SensorDeviceImpl::setCoordinateFrame, coordframe, true);
+}
+
+SensorDevice::CoordinateFrame SensorDeviceImpl::GetCoordinateFrame() const
+{
+ return Coordinates;
+}
+
+Void SensorDeviceImpl::setCoordinateFrame(CoordinateFrame coordframe)
+{
+
+ Coordinates = coordframe;
+
+ // Read the original coordinate frame, then try to change it.
+ SensorConfigImpl scfg;
+ if (GetInternalDevice()->GetFeatureReport(scfg.Buffer, SensorConfigImpl::PacketSize))
+ {
+ scfg.Unpack();
+ }
+
+ scfg.SetSensorCoordinates(coordframe == Coord_Sensor);
+ scfg.Pack();
+
+ GetInternalDevice()->SetFeatureReport(scfg.Buffer, SensorConfigImpl::PacketSize);
+
+ // Re-read the state, in case of older firmware that doesn't support Sensor coordinates.
+ if (GetInternalDevice()->GetFeatureReport(scfg.Buffer, SensorConfigImpl::PacketSize))
+ {
+ scfg.Unpack();
+ HWCoordinates = scfg.IsUsingSensorCoordinates() ? Coord_Sensor : Coord_HMD;
+ }
+ else
+ {
+ HWCoordinates = Coord_HMD;
+ }
+ return 0;
+}
+
+void SensorDeviceImpl::SetReportRate(unsigned rateHz)
+{
+ // Push call with wait.
+ GetManagerImpl()->GetThreadQueue()->
+ PushCall(this, &SensorDeviceImpl::setReportRate, rateHz, true);
+}
+
+unsigned SensorDeviceImpl::GetReportRate() const
+{
+ // Read the original configuration
+ SensorConfigImpl scfg;
+ if (GetInternalDevice()->GetFeatureReport(scfg.Buffer, SensorConfigImpl::PacketSize))
+ {
+ scfg.Unpack();
+ return Sensor_MaxReportRate / (scfg.PacketInterval + 1);
+ }
+ return 0; // error
+}
+
+Void SensorDeviceImpl::setReportRate(unsigned rateHz)
+{
+ // Read the original configuration
+ SensorConfigImpl scfg;
+ if (GetInternalDevice()->GetFeatureReport(scfg.Buffer, SensorConfigImpl::PacketSize))
+ {
+ scfg.Unpack();
+ }
+
+ if (rateHz > Sensor_MaxReportRate)
+ rateHz = Sensor_MaxReportRate;
+ else if (rateHz == 0)
+ rateHz = Sensor_DefaultReportRate;
+
+ scfg.PacketInterval = UInt16((Sensor_MaxReportRate / rateHz) - 1);
+
+ scfg.Pack();
+
+ GetInternalDevice()->SetFeatureReport(scfg.Buffer, SensorConfigImpl::PacketSize);
+ return 0;
+}
+
+void SensorDeviceImpl::SetMessageHandler(MessageHandler* handler)
+{
+ if (handler)
+ {
+ SequenceValid = false;
+ DeviceBase::SetMessageHandler(handler);
+ }
+ else
+ {
+ DeviceBase::SetMessageHandler(handler);
+ }
+}
+
+// Sensor reports data in the following coordinate system:
+// Accelerometer: 10^-4 m/s^2; X forward, Y right, Z Down.
+// Gyro: 10^-4 rad/s; X positive roll right, Y positive pitch up; Z positive yaw right.
+
+
+// We need to convert it to the following RHS coordinate system:
+// X right, Y Up, Z Back (out of screen)
+//
+Vector3f AccelFromBodyFrameUpdate(const TrackerSensors& update, UByte sampleNumber,
+ bool convertHMDToSensor = false)
+{
+ const TrackerSample& sample = update.Samples[sampleNumber];
+ float ax = (float)sample.AccelX;
+ float ay = (float)sample.AccelY;
+ float az = (float)sample.AccelZ;
+
+ Vector3f val = convertHMDToSensor ? Vector3f(ax, az, -ay) : Vector3f(ax, ay, az);
+ return val * 0.0001f;
+}
+
+
+Vector3f MagFromBodyFrameUpdate(const TrackerSensors& update,
+ bool convertHMDToSensor = false)
+{
+ // Note: Y and Z are swapped in comparison to the Accel.
+ // This accounts for DK1 sensor firmware axis swap, which should be undone in future releases.
+ if (!convertHMDToSensor)
+ {
+ return Vector3f( (float)update.MagX,
+ (float)update.MagZ,
+ (float)update.MagY) * 0.0001f;
+ }
+
+ return Vector3f( (float)update.MagX,
+ (float)update.MagY,
+ -(float)update.MagZ) * 0.0001f;
+}
+
+Vector3f EulerFromBodyFrameUpdate(const TrackerSensors& update, UByte sampleNumber,
+ bool convertHMDToSensor = false)
+{
+ const TrackerSample& sample = update.Samples[sampleNumber];
+ float gx = (float)sample.GyroX;
+ float gy = (float)sample.GyroY;
+ float gz = (float)sample.GyroZ;
+
+ Vector3f val = convertHMDToSensor ? Vector3f(gx, gz, -gy) : Vector3f(gx, gy, gz);
+ return val * 0.0001f;
+}
+
+
+void SensorDeviceImpl::onTrackerMessage(TrackerMessage* message)
+{
+ if (message->Type != TrackerMessage_Sensors)
+ return;
+
+ const float timeUnit = (1.0f / 1000.f);
+ TrackerSensors& s = message->Sensors;
+
+
+ // Call OnMessage() within a lock to avoid conflicts with handlers.
+ Lock::Locker scopeLock(HandlerRef.GetLock());
+
+
+ if (SequenceValid)
+ {
+ unsigned timestampDelta;
+
+ if (s.Timestamp < LastTimestamp)
+ timestampDelta = ((((int)s.Timestamp) + 0x10000) - (int)LastTimestamp);
+ else
+ timestampDelta = (s.Timestamp - LastTimestamp);
+
+ // If we missed a small number of samples, replicate the last sample.
+ if ((timestampDelta > LastSampleCount) && (timestampDelta <= 254))
+ {
+ if (HandlerRef.GetHandler())
+ {
+ MessageBodyFrame sensors(this);
+ sensors.TimeDelta = (timestampDelta - LastSampleCount) * timeUnit;
+ sensors.Acceleration = LastAcceleration;
+ sensors.RotationRate = LastRotationRate;
+ sensors.MagneticField = LastMagneticField;
+ sensors.Temperature = LastTemperature;
+
+ HandlerRef.GetHandler()->OnMessage(sensors);
+ }
+ }
+ }
+ else
+ {
+ LastAcceleration = Vector3f(0);
+ LastRotationRate = Vector3f(0);
+ LastMagneticField= Vector3f(0);
+ LastTemperature = 0;
+ SequenceValid = true;
+ }
+
+ LastSampleCount = s.SampleCount;
+ LastTimestamp = s.Timestamp;
+
+ bool convertHMDToSensor = (Coordinates == Coord_Sensor) && (HWCoordinates == Coord_HMD);
+
+ if (HandlerRef.GetHandler())
+ {
+ MessageBodyFrame sensors(this);
+ UByte iterations = s.SampleCount;
+
+ if (s.SampleCount > 3)
+ {
+ iterations = 3;
+ sensors.TimeDelta = (s.SampleCount - 2) * timeUnit;
+ }
+ else
+ {
+ sensors.TimeDelta = timeUnit;
+ }
+
+ for (UByte i = 0; i < iterations; i++)
+ {
+ sensors.Acceleration = AccelFromBodyFrameUpdate(s, i, convertHMDToSensor);
+ sensors.RotationRate = EulerFromBodyFrameUpdate(s, i, convertHMDToSensor);
+ sensors.MagneticField= MagFromBodyFrameUpdate(s, convertHMDToSensor);
+ sensors.Temperature = s.Temperature * 0.01f;
+ HandlerRef.GetHandler()->OnMessage(sensors);
+ // TimeDelta for the last two sample is always fixed.
+ sensors.TimeDelta = timeUnit;
+ }
+
+ LastAcceleration = sensors.Acceleration;
+ LastRotationRate = sensors.RotationRate;
+ LastMagneticField= sensors.MagneticField;
+ LastTemperature = sensors.Temperature;
+ }
+ else
+ {
+ UByte i = (s.SampleCount > 3) ? 2 : (s.SampleCount - 1);
+ LastAcceleration = AccelFromBodyFrameUpdate(s, i, convertHMDToSensor);
+ LastRotationRate = EulerFromBodyFrameUpdate(s, i, convertHMDToSensor);
+ LastMagneticField = MagFromBodyFrameUpdate(s, convertHMDToSensor);
+ LastTemperature = s.Temperature * 0.01f;
+ }
+}
+
+} // namespace OVR
+
+
diff --git a/LibOVR/Src/OVR_SensorImpl.h b/LibOVR/Src/OVR_SensorImpl.h
index 890d621..6ad1628 100644
--- a/LibOVR/Src/OVR_SensorImpl.h
+++ b/LibOVR/Src/OVR_SensorImpl.h
@@ -1,208 +1,208 @@
-/************************************************************************************
-
-Filename : OVR_SensorImpl.h
-Content : Sensor device specific implementation.
-Created : March 7, 2013
-Authors : Lee Cooper
-
-Copyright : Copyright 2013 Oculus VR, Inc. All Rights reserved.
-
-Use of this software is subject to the terms of the Oculus license
-agreement provided at the time of installation or download, or which
-otherwise accompanies this software in either electronic or hard copy form.
-
-*************************************************************************************/
-
-#ifndef OVR_SensorImpl_h
-#define OVR_SensorImpl_h
-
-#include "OVR_HIDDeviceImpl.h"
-
-namespace OVR {
-
-struct TrackerMessage;
-class ExternalVisitor;
-
-//-------------------------------------------------------------------------------------
-// SensorDeviceFactory enumerates Oculus Sensor devices.
-class SensorDeviceFactory : public DeviceFactory
-{
-public:
- static SensorDeviceFactory Instance;
-
- // Enumerates devices, creating and destroying relevant objects in manager.
- virtual void EnumerateDevices(EnumerateVisitor& visitor);
-
- virtual bool MatchVendorProduct(UInt16 vendorId, UInt16 productId) const;
- virtual bool DetectHIDDevice(DeviceManager* pdevMgr, const HIDDeviceDesc& desc);
-protected:
- DeviceManager* getManager() const { return (DeviceManager*) pManager; }
-};
-
-
-// Describes a single a Oculus Sensor device and supports creating its instance.
-class SensorDeviceCreateDesc : public HIDDeviceCreateDesc
-{
-public:
- SensorDeviceCreateDesc(DeviceFactory* factory, const HIDDeviceDesc& hidDesc)
- : HIDDeviceCreateDesc(factory, Device_Sensor, hidDesc) { }
-
- virtual DeviceCreateDesc* Clone() const
- {
- return new SensorDeviceCreateDesc(*this);
- }
-
- virtual DeviceBase* NewDeviceInstance();
-
- virtual MatchResult MatchDevice(const DeviceCreateDesc& other,
- DeviceCreateDesc**) const
- {
- if ((other.Type == Device_Sensor) && (pFactory == other.pFactory))
- {
- const SensorDeviceCreateDesc& s2 = (const SensorDeviceCreateDesc&) other;
- if (MatchHIDDevice(s2.HIDDesc))
- return Match_Found;
- }
- return Match_None;
- }
-
- virtual bool MatchHIDDevice(const HIDDeviceDesc& hidDesc) const
- {
- // should paths comparison be case insensitive?
- return ((HIDDesc.Path.CompareNoCase(hidDesc.Path) == 0) &&
- (HIDDesc.SerialNumber == hidDesc.SerialNumber));
- }
-
- virtual bool GetDeviceInfo(DeviceInfo* info) const;
-};
-
-
-//-------------------------------------------------------------------------------------
-// ***** OVR::SensorDisplayInfoImpl
-
-// DisplayInfo obtained from sensor; these values are used to report distortion
-// settings and other coefficients.
-// Older SensorDisplayInfo will have all zeros, causing the library to apply hard-coded defaults.
-// Currently, only resolutions and sizes are used.
-struct SensorDisplayInfoImpl
-{
- enum { PacketSize = 56 };
- UByte Buffer[PacketSize];
-
- enum
- {
- Mask_BaseFmt = 0x0f,
- Mask_OptionFmts = 0xf0,
- Base_None = 0,
- Base_ScreenOnly = 1,
- Base_Distortion = 2,
- };
-
- UInt16 CommandId;
- UByte DistortionType;
- UInt16 HResolution, VResolution;
- float HScreenSize, VScreenSize;
- float VCenter;
- float LensSeparation;
- float EyeToScreenDistance[2];
- float DistortionK[6];
-
- SensorDisplayInfoImpl();
-
- void Unpack();
-};
-
-
-//-------------------------------------------------------------------------------------
-// ***** OVR::SensorDeviceImpl
-
-// Oculus Sensor interface.
-
-class SensorDeviceImpl : public HIDDeviceImpl<OVR::SensorDevice>
-{
-public:
- SensorDeviceImpl(SensorDeviceCreateDesc* createDesc);
- ~SensorDeviceImpl();
-
-
- // DeviceCommaon interface
- virtual bool Initialize(DeviceBase* parent);
- virtual void Shutdown();
-
- virtual void SetMessageHandler(MessageHandler* handler);
-
- // HIDDevice::Notifier interface.
- virtual void OnInputReport(UByte* pData, UInt32 length);
- virtual UInt64 OnTicks(UInt64 ticksMks);
-
- // HMD-Mounted sensor has a different coordinate frame.
- virtual void SetCoordinateFrame(CoordinateFrame coordframe);
- virtual CoordinateFrame GetCoordinateFrame() const;
-
- // SensorDevice interface
- virtual bool SetRange(const SensorRange& range, bool waitFlag);
- virtual void GetRange(SensorRange* range) const;
-
- // Sets report rate (in Hz) of MessageBodyFrame messages (delivered through MessageHandler::OnMessage call).
- // Currently supported maximum rate is 1000Hz. If the rate is set to 500 or 333 Hz then OnMessage will be
- // called twice or thrice at the same 'tick'.
- // If the rate is < 333 then the OnMessage / MessageBodyFrame will be called three
- // times for each 'tick': the first call will contain averaged values, the second
- // and third calls will provide with most recent two recorded samples.
- virtual void SetReportRate(unsigned rateHz);
- // Returns currently set report rate, in Hz. If 0 - error occurred.
- // Note, this value may be different from the one provided for SetReportRate. The return
- // value will contain the actual rate.
- virtual unsigned GetReportRate() const;
-
- // Hack to create HMD device from sensor display info.
- static void EnumerateHMDFromSensorDisplayInfo(const SensorDisplayInfoImpl& displayInfo,
- DeviceFactory::EnumerateVisitor& visitor);
-protected:
-
- void openDevice();
- void closeDeviceOnError();
-
- Void setCoordinateFrame(CoordinateFrame coordframe);
- bool setRange(const SensorRange& range);
-
- Void setReportRate(unsigned rateHz);
-
- // Called for decoded messages
- void onTrackerMessage(TrackerMessage* message);
-
- // Helpers to reduce casting.
-/*
- SensorDeviceCreateDesc* getCreateDesc() const
- { return (SensorDeviceCreateDesc*)pCreateDesc.GetPtr(); }
-
- HIDDeviceDesc* getHIDDesc() const
- { return &getCreateDesc()->HIDDesc; }
-*/
-
- // Set if the sensor is located on the HMD.
- // Older prototype firmware doesn't support changing HW coordinates,
- // so we track its state.
- CoordinateFrame Coordinates;
- CoordinateFrame HWCoordinates;
- UInt64 NextKeepAliveTicks;
-
- bool SequenceValid;
- SInt16 LastTimestamp;
- UByte LastSampleCount;
- float LastTemperature;
- Vector3f LastAcceleration;
- Vector3f LastRotationRate;
- Vector3f LastMagneticField;
-
- // Current sensor range obtained from device.
- SensorRange MaxValidRange;
- SensorRange CurrentRange;
-
- UInt16 OldCommandId;
-};
-
-
-} // namespace OVR
-
-#endif // OVR_SensorImpl_h
+/************************************************************************************
+
+Filename : OVR_SensorImpl.h
+Content : Sensor device specific implementation.
+Created : March 7, 2013
+Authors : Lee Cooper
+
+Copyright : Copyright 2013 Oculus VR, Inc. All Rights reserved.
+
+Use of this software is subject to the terms of the Oculus license
+agreement provided at the time of installation or download, or which
+otherwise accompanies this software in either electronic or hard copy form.
+
+*************************************************************************************/
+
+#ifndef OVR_SensorImpl_h
+#define OVR_SensorImpl_h
+
+#include "OVR_HIDDeviceImpl.h"
+
+namespace OVR {
+
+struct TrackerMessage;
+class ExternalVisitor;
+
+//-------------------------------------------------------------------------------------
+// SensorDeviceFactory enumerates Oculus Sensor devices.
+class SensorDeviceFactory : public DeviceFactory
+{
+public:
+ static SensorDeviceFactory Instance;
+
+ // Enumerates devices, creating and destroying relevant objects in manager.
+ virtual void EnumerateDevices(EnumerateVisitor& visitor);
+
+ virtual bool MatchVendorProduct(UInt16 vendorId, UInt16 productId) const;
+ virtual bool DetectHIDDevice(DeviceManager* pdevMgr, const HIDDeviceDesc& desc);
+protected:
+ DeviceManager* getManager() const { return (DeviceManager*) pManager; }
+};
+
+
+// Describes a single a Oculus Sensor device and supports creating its instance.
+class SensorDeviceCreateDesc : public HIDDeviceCreateDesc
+{
+public:
+ SensorDeviceCreateDesc(DeviceFactory* factory, const HIDDeviceDesc& hidDesc)
+ : HIDDeviceCreateDesc(factory, Device_Sensor, hidDesc) { }
+
+ virtual DeviceCreateDesc* Clone() const
+ {
+ return new SensorDeviceCreateDesc(*this);
+ }
+
+ virtual DeviceBase* NewDeviceInstance();
+
+ virtual MatchResult MatchDevice(const DeviceCreateDesc& other,
+ DeviceCreateDesc**) const
+ {
+ if ((other.Type == Device_Sensor) && (pFactory == other.pFactory))
+ {
+ const SensorDeviceCreateDesc& s2 = (const SensorDeviceCreateDesc&) other;
+ if (MatchHIDDevice(s2.HIDDesc))
+ return Match_Found;
+ }
+ return Match_None;
+ }
+
+ virtual bool MatchHIDDevice(const HIDDeviceDesc& hidDesc) const
+ {
+ // should paths comparison be case insensitive?
+ return ((HIDDesc.Path.CompareNoCase(hidDesc.Path) == 0) &&
+ (HIDDesc.SerialNumber == hidDesc.SerialNumber));
+ }
+
+ virtual bool GetDeviceInfo(DeviceInfo* info) const;
+};
+
+
+//-------------------------------------------------------------------------------------
+// ***** OVR::SensorDisplayInfoImpl
+
+// DisplayInfo obtained from sensor; these values are used to report distortion
+// settings and other coefficients.
+// Older SensorDisplayInfo will have all zeros, causing the library to apply hard-coded defaults.
+// Currently, only resolutions and sizes are used.
+struct SensorDisplayInfoImpl
+{
+ enum { PacketSize = 56 };
+ UByte Buffer[PacketSize];
+
+ enum
+ {
+ Mask_BaseFmt = 0x0f,
+ Mask_OptionFmts = 0xf0,
+ Base_None = 0,
+ Base_ScreenOnly = 1,
+ Base_Distortion = 2,
+ };
+
+ UInt16 CommandId;
+ UByte DistortionType;
+ UInt16 HResolution, VResolution;
+ float HScreenSize, VScreenSize;
+ float VCenter;
+ float LensSeparation;
+ float EyeToScreenDistance[2];
+ float DistortionK[6];
+
+ SensorDisplayInfoImpl();
+
+ void Unpack();
+};
+
+
+//-------------------------------------------------------------------------------------
+// ***** OVR::SensorDeviceImpl
+
+// Oculus Sensor interface.
+
+class SensorDeviceImpl : public HIDDeviceImpl<OVR::SensorDevice>
+{
+public:
+ SensorDeviceImpl(SensorDeviceCreateDesc* createDesc);
+ ~SensorDeviceImpl();
+
+
+ // DeviceCommaon interface
+ virtual bool Initialize(DeviceBase* parent);
+ virtual void Shutdown();
+
+ virtual void SetMessageHandler(MessageHandler* handler);
+
+ // HIDDevice::Notifier interface.
+ virtual void OnInputReport(UByte* pData, UInt32 length);
+ virtual UInt64 OnTicks(UInt64 ticksMks);
+
+ // HMD-Mounted sensor has a different coordinate frame.
+ virtual void SetCoordinateFrame(CoordinateFrame coordframe);
+ virtual CoordinateFrame GetCoordinateFrame() const;
+
+ // SensorDevice interface
+ virtual bool SetRange(const SensorRange& range, bool waitFlag);
+ virtual void GetRange(SensorRange* range) const;
+
+ // Sets report rate (in Hz) of MessageBodyFrame messages (delivered through MessageHandler::OnMessage call).
+ // Currently supported maximum rate is 1000Hz. If the rate is set to 500 or 333 Hz then OnMessage will be
+ // called twice or thrice at the same 'tick'.
+ // If the rate is < 333 then the OnMessage / MessageBodyFrame will be called three
+ // times for each 'tick': the first call will contain averaged values, the second
+ // and third calls will provide with most recent two recorded samples.
+ virtual void SetReportRate(unsigned rateHz);
+ // Returns currently set report rate, in Hz. If 0 - error occurred.
+ // Note, this value may be different from the one provided for SetReportRate. The return
+ // value will contain the actual rate.
+ virtual unsigned GetReportRate() const;
+
+ // Hack to create HMD device from sensor display info.
+ static void EnumerateHMDFromSensorDisplayInfo(const SensorDisplayInfoImpl& displayInfo,
+ DeviceFactory::EnumerateVisitor& visitor);
+protected:
+
+ void openDevice();
+ void closeDeviceOnError();
+
+ Void setCoordinateFrame(CoordinateFrame coordframe);
+ bool setRange(const SensorRange& range);
+
+ Void setReportRate(unsigned rateHz);
+
+ // Called for decoded messages
+ void onTrackerMessage(TrackerMessage* message);
+
+ // Helpers to reduce casting.
+/*
+ SensorDeviceCreateDesc* getCreateDesc() const
+ { return (SensorDeviceCreateDesc*)pCreateDesc.GetPtr(); }
+
+ HIDDeviceDesc* getHIDDesc() const
+ { return &getCreateDesc()->HIDDesc; }
+*/
+
+ // Set if the sensor is located on the HMD.
+ // Older prototype firmware doesn't support changing HW coordinates,
+ // so we track its state.
+ CoordinateFrame Coordinates;
+ CoordinateFrame HWCoordinates;
+ UInt64 NextKeepAliveTicks;
+
+ bool SequenceValid;
+ SInt16 LastTimestamp;
+ UByte LastSampleCount;
+ float LastTemperature;
+ Vector3f LastAcceleration;
+ Vector3f LastRotationRate;
+ Vector3f LastMagneticField;
+
+ // Current sensor range obtained from device.
+ SensorRange MaxValidRange;
+ SensorRange CurrentRange;
+
+ UInt16 OldCommandId;
+};
+
+
+} // namespace OVR
+
+#endif // OVR_SensorImpl_h
diff --git a/LibOVR/Src/OVR_ThreadCommandQueue.cpp b/LibOVR/Src/OVR_ThreadCommandQueue.cpp
index d9dbab3..00a5a39 100644
--- a/LibOVR/Src/OVR_ThreadCommandQueue.cpp
+++ b/LibOVR/Src/OVR_ThreadCommandQueue.cpp
@@ -1,370 +1,370 @@
-/************************************************************************************
-
-PublicHeader: None
-Filename : OVR_ThreadCommandQueue.cpp
-Content : Command queue for operations executed on a thread
-Created : October 29, 2012
-
-Copyright : Copyright 2012 Oculus VR, Inc. All Rights reserved.
-
-Use of this software is subject to the terms of the Oculus license
-agreement provided at the time of installation or download, or which
-otherwise accompanies this software in either electronic or hard copy form.
-
-************************************************************************************/
-
-#include "OVR_ThreadCommandQueue.h"
-
-namespace OVR {
-
-
-//------------------------------------------------------------------------
-// ***** CircularBuffer
-
-// CircularBuffer is a FIFO buffer implemented in a single block of memory,
-// which allows writing and reading variable-size data chucks. Write fails
-// if buffer is full.
-
-class CircularBuffer
-{
- enum {
- AlignSize = 16,
- AlignMask = AlignSize - 1
- };
-
- UByte* pBuffer;
- UPInt Size;
- UPInt Tail; // Byte offset of next item to be popped.
- UPInt Head; // Byte offset of where next push will take place.
- UPInt End; // When Head < Tail, this is used instead of Size.
-
- inline UPInt roundUpSize(UPInt size)
- { return (size + AlignMask) & ~(UPInt)AlignMask; }
-
-public:
-
- CircularBuffer(UPInt size)
- : Size(size), Tail(0), Head(0), End(0)
- {
- pBuffer = (UByte*)OVR_ALLOC_ALIGNED(roundUpSize(size), AlignSize);
- }
- ~CircularBuffer()
- {
- // For ThreadCommands, we must consume everything before shutdown.
- OVR_ASSERT(IsEmpty());
- OVR_FREE_ALIGNED(pBuffer);
- }
-
- bool IsEmpty() const { return (Head == Tail); }
-
- // Allocates a state block of specified size and advances pointers,
- // returning 0 if buffer is full.
- UByte* Write(UPInt size);
-
- // Returns a pointer to next available data block; 0 if none available.
- UByte* ReadBegin()
- { return (Head != Tail) ? (pBuffer + Tail) : 0; }
- // Consumes data of specified size; this must match size passed to Write.
- void ReadEnd(UPInt size);
-};
-
-
-// Allocates a state block of specified size and advances pointers,
-// returning 0 if buffer is full.
-UByte* CircularBuffer::Write(UPInt size)
-{
- UByte* p = 0;
-
- size = roundUpSize(size);
- // Since this is circular buffer, always allow at least one item.
- OVR_ASSERT(size < Size/2);
-
- if (Head >= Tail)
- {
- OVR_ASSERT(End == 0);
-
- if (size <= (Size - Head))
- {
- p = pBuffer + Head;
- Head += size;
- }
- else if (size < Tail)
- {
- p = pBuffer;
- End = Head;
- Head = size;
- OVR_ASSERT(Head != Tail);
- }
- }
- else
- {
- OVR_ASSERT(End != 0);
-
- if ((Tail - Head) > size)
- {
- p = pBuffer + Head;
- Head += size;
- OVR_ASSERT(Head != Tail);
- }
- }
-
- return p;
-}
-
-void CircularBuffer::ReadEnd(UPInt size)
-{
- OVR_ASSERT(Head != Tail);
- size = roundUpSize(size);
-
- Tail += size;
- if (Tail == End)
- {
- Tail = End = 0;
- }
- else if (Tail == Head)
- {
- OVR_ASSERT(End == 0);
- Tail = Head = 0;
- }
-}
-
-
-//-------------------------------------------------------------------------------------
-// ***** ThreadCommand
-
-ThreadCommand::PopBuffer::~PopBuffer()
-{
- if (Size)
- Destruct<ThreadCommand>(toCommand());
-}
-
-void ThreadCommand::PopBuffer::InitFromBuffer(void* data)
-{
- ThreadCommand* cmd = (ThreadCommand*)data;
- OVR_ASSERT(cmd->Size <= MaxSize);
-
- if (Size)
- Destruct<ThreadCommand>(toCommand());
- Size = cmd->Size;
- memcpy(Buffer, (void*)cmd, Size);
-}
-
-void ThreadCommand::PopBuffer::Execute()
-{
- ThreadCommand* command = toCommand();
- OVR_ASSERT(command);
- command->Execute();
- if (NeedsWait())
- GetEvent()->PulseEvent();
-}
-
-//-------------------------------------------------------------------------------------
-
-class ThreadCommandQueueImpl : public NewOverrideBase
-{
- typedef ThreadCommand::NotifyEvent NotifyEvent;
- friend class ThreadCommandQueue;
-
-public:
-
- ThreadCommandQueueImpl(ThreadCommandQueue* queue)
- : pQueue(queue), CommandBuffer(2048),
- ExitEnqueued(false), ExitProcessed(false)
- {
- }
- ~ThreadCommandQueueImpl();
-
-
- bool PushCommand(const ThreadCommand& command);
- bool PopCommand(ThreadCommand::PopBuffer* popBuffer);
-
-
- // ExitCommand is used by notify us that Thread is shutting down.
- struct ExitCommand : public ThreadCommand
- {
- ThreadCommandQueueImpl* pImpl;
-
- ExitCommand(ThreadCommandQueueImpl* impl, bool wait)
- : ThreadCommand(sizeof(ExitCommand), wait, true), pImpl(impl) { }
-
- virtual void Execute() const
- {
- Lock::Locker lock(&pImpl->QueueLock);
- pImpl->ExitProcessed = true;
- }
- virtual ThreadCommand* CopyConstruct(void* p) const
- { return Construct<ExitCommand>(p, *this); }
- };
-
-
- NotifyEvent* AllocNotifyEvent_NTS()
- {
- NotifyEvent* p = AvailableEvents.GetFirst();
-
- if (!AvailableEvents.IsNull(p))
- p->RemoveNode();
- else
- p = new NotifyEvent;
- return p;
- }
-
- void FreeNotifyEvent_NTS(NotifyEvent* p)
- {
- AvailableEvents.PushBack(p);
- }
-
- void FreeNotifyEvents_NTS()
- {
- while(!AvailableEvents.IsEmpty())
- {
- NotifyEvent* p = AvailableEvents.GetFirst();
- p->RemoveNode();
- delete p;
- }
- }
-
- ThreadCommandQueue* pQueue;
- Lock QueueLock;
- volatile bool ExitEnqueued;
- volatile bool ExitProcessed;
- List<NotifyEvent> AvailableEvents;
- List<NotifyEvent> BlockedProducers;
- CircularBuffer CommandBuffer;
-};
-
-
-
-ThreadCommandQueueImpl::~ThreadCommandQueueImpl()
-{
- Lock::Locker lock(&QueueLock);
- OVR_ASSERT(BlockedProducers.IsEmpty());
- FreeNotifyEvents_NTS();
-}
-
-bool ThreadCommandQueueImpl::PushCommand(const ThreadCommand& command)
-{
- ThreadCommand::NotifyEvent* completeEvent = 0;
- ThreadCommand::NotifyEvent* queueAvailableEvent = 0;
-
- // Repeat writing command into buffer until it is available.
- do {
-
- { // Lock Scope
- Lock::Locker lock(&QueueLock);
-
- if (queueAvailableEvent)
- {
- FreeNotifyEvent_NTS(queueAvailableEvent);
- queueAvailableEvent = 0;
- }
-
- // Don't allow any commands after PushExitCommand() is called.
- if (ExitEnqueued && !command.ExitFlag)
- return false;
-
-
- bool bufferWasEmpty = CommandBuffer.IsEmpty();
- UByte* buffer = CommandBuffer.Write(command.GetSize());
- if (buffer)
- {
- ThreadCommand* c = command.CopyConstruct(buffer);
- if (c->NeedsWait())
- completeEvent = c->pEvent = AllocNotifyEvent_NTS();
- // Signal-waker consumer when we add data to buffer.
- if (bufferWasEmpty)
- pQueue->OnPushNonEmpty_Locked();
- break;
- }
-
- queueAvailableEvent = AllocNotifyEvent_NTS();
- BlockedProducers.PushBack(queueAvailableEvent);
- } // Lock Scope
-
- queueAvailableEvent->Wait();
-
- } while(1);
-
- // Command was enqueued, wait if necessary.
- if (completeEvent)
- {
- completeEvent->Wait();
- Lock::Locker lock(&QueueLock);
- FreeNotifyEvent_NTS(completeEvent);
- }
-
- return true;
-}
-
-
-// Pops the next command from the thread queue, if any is available.
-bool ThreadCommandQueueImpl::PopCommand(ThreadCommand::PopBuffer* popBuffer)
-{
- Lock::Locker lock(&QueueLock);
-
- UByte* buffer = CommandBuffer.ReadBegin();
- if (!buffer)
- {
- // Notify thread while in lock scope, enabling initialization of wait.
- pQueue->OnPopEmpty_Locked();
- return false;
- }
-
- popBuffer->InitFromBuffer(buffer);
- CommandBuffer.ReadEnd(popBuffer->GetSize());
-
- if (!BlockedProducers.IsEmpty())
- {
- ThreadCommand::NotifyEvent* queueAvailableEvent = BlockedProducers.GetFirst();
- queueAvailableEvent->RemoveNode();
- queueAvailableEvent->PulseEvent();
- // Event is freed later by waiter.
- }
- return true;
-}
-
-
-//-------------------------------------------------------------------------------------
-
-ThreadCommandQueue::ThreadCommandQueue()
-{
- pImpl = new ThreadCommandQueueImpl(this);
-}
-ThreadCommandQueue::~ThreadCommandQueue()
-{
- delete pImpl;
-}
-
-bool ThreadCommandQueue::PushCommand(const ThreadCommand& command)
-{
- return pImpl->PushCommand(command);
-}
-
-bool ThreadCommandQueue::PopCommand(ThreadCommand::PopBuffer* popBuffer)
-{
- return pImpl->PopCommand(popBuffer);
-}
-
-void ThreadCommandQueue::PushExitCommand(bool wait)
-{
- // Exit is processed in two stages:
- // - First, ExitEnqueued flag is set to block further commands from queuing up.
- // - Second, the actual exit call is processed on the consumer thread, flushing
- // any prior commands.
- // IsExiting() only returns true after exit has flushed.
- {
- Lock::Locker lock(&pImpl->QueueLock);
- if (pImpl->ExitEnqueued)
- return;
- pImpl->ExitEnqueued = true;
- }
-
- PushCommand(ThreadCommandQueueImpl::ExitCommand(pImpl, wait));
-}
-
-bool ThreadCommandQueue::IsExiting() const
-{
- return pImpl->ExitProcessed;
-}
-
-
-} // namespace OVR
+/************************************************************************************
+
+PublicHeader: None
+Filename : OVR_ThreadCommandQueue.cpp
+Content : Command queue for operations executed on a thread
+Created : October 29, 2012
+
+Copyright : Copyright 2012 Oculus VR, Inc. All Rights reserved.
+
+Use of this software is subject to the terms of the Oculus license
+agreement provided at the time of installation or download, or which
+otherwise accompanies this software in either electronic or hard copy form.
+
+************************************************************************************/
+
+#include "OVR_ThreadCommandQueue.h"
+
+namespace OVR {
+
+
+//------------------------------------------------------------------------
+// ***** CircularBuffer
+
+// CircularBuffer is a FIFO buffer implemented in a single block of memory,
+// which allows writing and reading variable-size data chucks. Write fails
+// if buffer is full.
+
+class CircularBuffer
+{
+ enum {
+ AlignSize = 16,
+ AlignMask = AlignSize - 1
+ };
+
+ UByte* pBuffer;
+ UPInt Size;
+ UPInt Tail; // Byte offset of next item to be popped.
+ UPInt Head; // Byte offset of where next push will take place.
+ UPInt End; // When Head < Tail, this is used instead of Size.
+
+ inline UPInt roundUpSize(UPInt size)
+ { return (size + AlignMask) & ~(UPInt)AlignMask; }
+
+public:
+
+ CircularBuffer(UPInt size)
+ : Size(size), Tail(0), Head(0), End(0)
+ {
+ pBuffer = (UByte*)OVR_ALLOC_ALIGNED(roundUpSize(size), AlignSize);
+ }
+ ~CircularBuffer()
+ {
+ // For ThreadCommands, we must consume everything before shutdown.
+ OVR_ASSERT(IsEmpty());
+ OVR_FREE_ALIGNED(pBuffer);
+ }
+
+ bool IsEmpty() const { return (Head == Tail); }
+
+ // Allocates a state block of specified size and advances pointers,
+ // returning 0 if buffer is full.
+ UByte* Write(UPInt size);
+
+ // Returns a pointer to next available data block; 0 if none available.
+ UByte* ReadBegin()
+ { return (Head != Tail) ? (pBuffer + Tail) : 0; }
+ // Consumes data of specified size; this must match size passed to Write.
+ void ReadEnd(UPInt size);
+};
+
+
+// Allocates a state block of specified size and advances pointers,
+// returning 0 if buffer is full.
+UByte* CircularBuffer::Write(UPInt size)
+{
+ UByte* p = 0;
+
+ size = roundUpSize(size);
+ // Since this is circular buffer, always allow at least one item.
+ OVR_ASSERT(size < Size/2);
+
+ if (Head >= Tail)
+ {
+ OVR_ASSERT(End == 0);
+
+ if (size <= (Size - Head))
+ {
+ p = pBuffer + Head;
+ Head += size;
+ }
+ else if (size < Tail)
+ {
+ p = pBuffer;
+ End = Head;
+ Head = size;
+ OVR_ASSERT(Head != Tail);
+ }
+ }
+ else
+ {
+ OVR_ASSERT(End != 0);
+
+ if ((Tail - Head) > size)
+ {
+ p = pBuffer + Head;
+ Head += size;
+ OVR_ASSERT(Head != Tail);
+ }
+ }
+
+ return p;
+}
+
+void CircularBuffer::ReadEnd(UPInt size)
+{
+ OVR_ASSERT(Head != Tail);
+ size = roundUpSize(size);
+
+ Tail += size;
+ if (Tail == End)
+ {
+ Tail = End = 0;
+ }
+ else if (Tail == Head)
+ {
+ OVR_ASSERT(End == 0);
+ Tail = Head = 0;
+ }
+}
+
+
+//-------------------------------------------------------------------------------------
+// ***** ThreadCommand
+
+ThreadCommand::PopBuffer::~PopBuffer()
+{
+ if (Size)
+ Destruct<ThreadCommand>(toCommand());
+}
+
+void ThreadCommand::PopBuffer::InitFromBuffer(void* data)
+{
+ ThreadCommand* cmd = (ThreadCommand*)data;
+ OVR_ASSERT(cmd->Size <= MaxSize);
+
+ if (Size)
+ Destruct<ThreadCommand>(toCommand());
+ Size = cmd->Size;
+ memcpy(Buffer, (void*)cmd, Size);
+}
+
+void ThreadCommand::PopBuffer::Execute()
+{
+ ThreadCommand* command = toCommand();
+ OVR_ASSERT(command);
+ command->Execute();
+ if (NeedsWait())
+ GetEvent()->PulseEvent();
+}
+
+//-------------------------------------------------------------------------------------
+
+class ThreadCommandQueueImpl : public NewOverrideBase
+{
+ typedef ThreadCommand::NotifyEvent NotifyEvent;
+ friend class ThreadCommandQueue;
+
+public:
+
+ ThreadCommandQueueImpl(ThreadCommandQueue* queue)
+ : pQueue(queue), CommandBuffer(2048),
+ ExitEnqueued(false), ExitProcessed(false)
+ {
+ }
+ ~ThreadCommandQueueImpl();
+
+
+ bool PushCommand(const ThreadCommand& command);
+ bool PopCommand(ThreadCommand::PopBuffer* popBuffer);
+
+
+ // ExitCommand is used by notify us that Thread is shutting down.
+ struct ExitCommand : public ThreadCommand
+ {
+ ThreadCommandQueueImpl* pImpl;
+
+ ExitCommand(ThreadCommandQueueImpl* impl, bool wait)
+ : ThreadCommand(sizeof(ExitCommand), wait, true), pImpl(impl) { }
+
+ virtual void Execute() const
+ {
+ Lock::Locker lock(&pImpl->QueueLock);
+ pImpl->ExitProcessed = true;
+ }
+ virtual ThreadCommand* CopyConstruct(void* p) const
+ { return Construct<ExitCommand>(p, *this); }
+ };
+
+
+ NotifyEvent* AllocNotifyEvent_NTS()
+ {
+ NotifyEvent* p = AvailableEvents.GetFirst();
+
+ if (!AvailableEvents.IsNull(p))
+ p->RemoveNode();
+ else
+ p = new NotifyEvent;
+ return p;
+ }
+
+ void FreeNotifyEvent_NTS(NotifyEvent* p)
+ {
+ AvailableEvents.PushBack(p);
+ }
+
+ void FreeNotifyEvents_NTS()
+ {
+ while(!AvailableEvents.IsEmpty())
+ {
+ NotifyEvent* p = AvailableEvents.GetFirst();
+ p->RemoveNode();
+ delete p;
+ }
+ }
+
+ ThreadCommandQueue* pQueue;
+ Lock QueueLock;
+ volatile bool ExitEnqueued;
+ volatile bool ExitProcessed;
+ List<NotifyEvent> AvailableEvents;
+ List<NotifyEvent> BlockedProducers;
+ CircularBuffer CommandBuffer;
+};
+
+
+
+ThreadCommandQueueImpl::~ThreadCommandQueueImpl()
+{
+ Lock::Locker lock(&QueueLock);
+ OVR_ASSERT(BlockedProducers.IsEmpty());
+ FreeNotifyEvents_NTS();
+}
+
+bool ThreadCommandQueueImpl::PushCommand(const ThreadCommand& command)
+{
+ ThreadCommand::NotifyEvent* completeEvent = 0;
+ ThreadCommand::NotifyEvent* queueAvailableEvent = 0;
+
+ // Repeat writing command into buffer until it is available.
+ do {
+
+ { // Lock Scope
+ Lock::Locker lock(&QueueLock);
+
+ if (queueAvailableEvent)
+ {
+ FreeNotifyEvent_NTS(queueAvailableEvent);
+ queueAvailableEvent = 0;
+ }
+
+ // Don't allow any commands after PushExitCommand() is called.
+ if (ExitEnqueued && !command.ExitFlag)
+ return false;
+
+
+ bool bufferWasEmpty = CommandBuffer.IsEmpty();
+ UByte* buffer = CommandBuffer.Write(command.GetSize());
+ if (buffer)
+ {
+ ThreadCommand* c = command.CopyConstruct(buffer);
+ if (c->NeedsWait())
+ completeEvent = c->pEvent = AllocNotifyEvent_NTS();
+ // Signal-waker consumer when we add data to buffer.
+ if (bufferWasEmpty)
+ pQueue->OnPushNonEmpty_Locked();
+ break;
+ }
+
+ queueAvailableEvent = AllocNotifyEvent_NTS();
+ BlockedProducers.PushBack(queueAvailableEvent);
+ } // Lock Scope
+
+ queueAvailableEvent->Wait();
+
+ } while(1);
+
+ // Command was enqueued, wait if necessary.
+ if (completeEvent)
+ {
+ completeEvent->Wait();
+ Lock::Locker lock(&QueueLock);
+ FreeNotifyEvent_NTS(completeEvent);
+ }
+
+ return true;
+}
+
+
+// Pops the next command from the thread queue, if any is available.
+bool ThreadCommandQueueImpl::PopCommand(ThreadCommand::PopBuffer* popBuffer)
+{
+ Lock::Locker lock(&QueueLock);
+
+ UByte* buffer = CommandBuffer.ReadBegin();
+ if (!buffer)
+ {
+ // Notify thread while in lock scope, enabling initialization of wait.
+ pQueue->OnPopEmpty_Locked();
+ return false;
+ }
+
+ popBuffer->InitFromBuffer(buffer);
+ CommandBuffer.ReadEnd(popBuffer->GetSize());
+
+ if (!BlockedProducers.IsEmpty())
+ {
+ ThreadCommand::NotifyEvent* queueAvailableEvent = BlockedProducers.GetFirst();
+ queueAvailableEvent->RemoveNode();
+ queueAvailableEvent->PulseEvent();
+ // Event is freed later by waiter.
+ }
+ return true;
+}
+
+
+//-------------------------------------------------------------------------------------
+
+ThreadCommandQueue::ThreadCommandQueue()
+{
+ pImpl = new ThreadCommandQueueImpl(this);
+}
+ThreadCommandQueue::~ThreadCommandQueue()
+{
+ delete pImpl;
+}
+
+bool ThreadCommandQueue::PushCommand(const ThreadCommand& command)
+{
+ return pImpl->PushCommand(command);
+}
+
+bool ThreadCommandQueue::PopCommand(ThreadCommand::PopBuffer* popBuffer)
+{
+ return pImpl->PopCommand(popBuffer);
+}
+
+void ThreadCommandQueue::PushExitCommand(bool wait)
+{
+ // Exit is processed in two stages:
+ // - First, ExitEnqueued flag is set to block further commands from queuing up.
+ // - Second, the actual exit call is processed on the consumer thread, flushing
+ // any prior commands.
+ // IsExiting() only returns true after exit has flushed.
+ {
+ Lock::Locker lock(&pImpl->QueueLock);
+ if (pImpl->ExitEnqueued)
+ return;
+ pImpl->ExitEnqueued = true;
+ }
+
+ PushCommand(ThreadCommandQueueImpl::ExitCommand(pImpl, wait));
+}
+
+bool ThreadCommandQueue::IsExiting() const
+{
+ return pImpl->ExitProcessed;
+}
+
+
+} // namespace OVR
diff --git a/LibOVR/Src/OVR_ThreadCommandQueue.h b/LibOVR/Src/OVR_ThreadCommandQueue.h
index 98d6228..b760278 100644
--- a/LibOVR/Src/OVR_ThreadCommandQueue.h
+++ b/LibOVR/Src/OVR_ThreadCommandQueue.h
@@ -1,308 +1,308 @@
-/************************************************************************************
-
-PublicHeader: None
-Filename : OVR_ThreadCommandQueue.h
-Content : Command queue for operations executed on a thread
-Created : October 29, 2012
-Author : Michael Antonov
-
-Copyright : Copyright 2012 Oculus VR, Inc. All Rights reserved.
-
-Use of this software is subject to the terms of the Oculus license
-agreement provided at the time of installation or download, or which
-otherwise accompanies this software in either electronic or hard copy form.
-
-************************************************************************************/
-
-#ifndef OVR_ThreadCommandQueue_h
-#define OVR_ThreadCommandQueue_h
-
-#include "Kernel/OVR_Types.h"
-#include "Kernel/OVR_List.h"
-#include "Kernel/OVR_Atomic.h"
-#include "Kernel/OVR_Threads.h"
-
-namespace OVR {
-
-class ThreadCommand;
-class ThreadCommandQueue;
-
-
-//-------------------------------------------------------------------------------------
-// ***** ThreadCommand
-
-// ThreadCommand is a base class implementation for commands stored in ThreadCommandQueue.
-class ThreadCommand
-{
-public:
-
- // NotifyEvent is used by ThreadCommandQueue::PushCallAndWait to notify the
- // calling (producer) thread when command is completed or queue slot is available.
- class NotifyEvent : public ListNode<NotifyEvent>, public NewOverrideBase
- {
- Event E;
- public:
- NotifyEvent() { }
-
- void Wait() { E.Wait(); }
- void PulseEvent() { E.PulseEvent(); }
- };
-
- // ThreadCommand::PopBuffer is temporary storage for a command popped off
- // by ThreadCommandQueue::PopCommand.
- class PopBuffer
- {
- enum { MaxSize = 256 };
-
- UPInt Size;
- union {
- UByte Buffer[MaxSize];
- UPInt Align;
- };
-
- ThreadCommand* toCommand() const { return (ThreadCommand*)Buffer; }
-
- public:
- PopBuffer() : Size(0) { }
- ~PopBuffer();
-
- void InitFromBuffer(void* data);
-
- bool HasCommand() const { return Size != 0; }
- UPInt GetSize() const { return Size; }
- bool NeedsWait() const { return toCommand()->NeedsWait(); }
- NotifyEvent* GetEvent() const { return toCommand()->pEvent; }
-
- // Execute the command and also notifies caller to finish waiting,
- // if necessary.
- void Execute();
- };
-
- UInt16 Size;
- bool WaitFlag;
- bool ExitFlag; // Marks the last exit command.
- NotifyEvent* pEvent;
-
- ThreadCommand(UPInt size, bool waitFlag, bool exitFlag = false)
- : Size((UInt16)size), WaitFlag(waitFlag), ExitFlag(exitFlag), pEvent(0) { }
- virtual ~ThreadCommand() { }
-
- bool NeedsWait() const { return WaitFlag; }
- UPInt GetSize() const { return Size; }
-
- virtual void Execute() const = 0;
- // Copy constructor used for serializing this to memory buffer.
- virtual ThreadCommand* CopyConstruct(void* p) const = 0;
-};
-
-
-//-------------------------------------------------------------------------------------
-
-// CleanType is a template that strips 'const' and '&' modifiers from the argument type;
-// for example, typename CleanType<A&>::Type is equivalent to A.
-template<class T> struct CleanType { typedef T Type; };
-template<class T> struct CleanType<T&> { typedef T Type; };
-template<class T> struct CleanType<const T> { typedef T Type; };
-template<class T> struct CleanType<const T&> { typedef T Type; };
-
-// SelfType is a template that yields the argument type. This helps avoid conflicts with
-// automatic template argument deduction for function calls when identical argument
-// is already defined.
-template<class T> struct SelfType { typedef T Type; };
-
-
-
-//-------------------------------------------------------------------------------------
-// ThreadCommand specializations for member functions with different number of
-// arguments and argument types.
-
-// Used to return nothing from a ThreadCommand, to avoid problems with 'void'.
-struct Void
-{
- Void() {}
- Void(int) {}
-};
-
-// ThreadCommand for member function with 0 arguments.
-template<class C, class R>
-class ThreadCommandMF0 : public ThreadCommand
-{
- typedef R (C::*FnPtr)();
- C* pClass;
- FnPtr pFn;
- R* pRet;
-
- void executeImpl() const
- {
- pRet ? (void)(*pRet = (pClass->*pFn)()) :
- (void)(pClass->*pFn)();
- }
-
-public:
- ThreadCommandMF0(C* pclass, FnPtr fn, R* ret, bool needsWait)
- : ThreadCommand(sizeof(ThreadCommandMF0), needsWait),
- pClass(pclass), pFn(fn), pRet(ret) { }
-
- virtual void Execute() const { executeImpl(); }
- virtual ThreadCommand* CopyConstruct(void* p) const
- { return Construct<ThreadCommandMF0>(p, *this); }
-};
-
-
-// ThreadCommand for member function with 1 argument.
-template<class C, class R, class A0>
-class ThreadCommandMF1 : public ThreadCommand
-{
- typedef R (C::*FnPtr)(A0);
- C* pClass;
- FnPtr pFn;
- R* pRet;
- typename CleanType<A0>::Type AVal0;
-
- void executeImpl() const
- {
- pRet ? (void)(*pRet = (pClass->*pFn)(AVal0)) :
- (void)(pClass->*pFn)(AVal0);
- }
-
-public:
- ThreadCommandMF1(C* pclass, FnPtr fn, R* ret, A0 a0, bool needsWait)
- : ThreadCommand(sizeof(ThreadCommandMF1), needsWait),
- pClass(pclass), pFn(fn), pRet(ret), AVal0(a0) { }
-
- virtual void Execute() const { executeImpl(); }
- virtual ThreadCommand* CopyConstruct(void* p) const
- { return Construct<ThreadCommandMF1>(p, *this); }
-};
-
-// ThreadCommand for member function with 2 arguments.
-template<class C, class R, class A0, class A1>
-class ThreadCommandMF2 : public ThreadCommand
-{
- typedef R (C::*FnPtr)(A0, A1);
- C* pClass;
- FnPtr pFn;
- R* pRet;
- typename CleanType<A0>::Type AVal0;
- typename CleanType<A1>::Type AVal1;
-
- void executeImpl() const
- {
- pRet ? (void)(*pRet = (pClass->*pFn)(AVal0, AVal1)) :
- (void)(pClass->*pFn)(AVal0, AVal1);
- }
-
-public:
- ThreadCommandMF2(C* pclass, FnPtr fn, R* ret, A0 a0, A1 a1, bool needsWait)
- : ThreadCommand(sizeof(ThreadCommandMF2), needsWait),
- pClass(pclass), pFn(fn), pRet(ret), AVal0(a0), AVal1(a1) { }
-
- virtual void Execute() const { executeImpl(); }
- virtual ThreadCommand* CopyConstruct(void* p) const
- { return Construct<ThreadCommandMF2>(p, *this); }
-};
-
-
-//-------------------------------------------------------------------------------------
-// ***** ThreadCommandQueue
-
-// ThreadCommandQueue is a queue of executable function-call commands intended to be
-// serviced by a single consumer thread. Commands are added to the queue with PushCall
-// and removed with PopCall; they are processed in FIFO order. Multiple producer threads
-// are supported and will be blocked if internal data buffer is full.
-
-class ThreadCommandQueue
-{
-public:
-
- ThreadCommandQueue();
- virtual ~ThreadCommandQueue();
-
-
- // Pops the next command from the thread queue, if any is available.
- // The command should be executed by calling popBuffer->Execute().
- // Returns 'false' if no command is available at the time of the call.
- bool PopCommand(ThreadCommand::PopBuffer* popBuffer);
-
- // Generic implementaion of PushCommand; enqueues a command for execution.
- // Returns 'false' if push failed, usually indicating thread shutdown.
- bool PushCommand(const ThreadCommand& command);
-
- //
- void PushExitCommand(bool wait);
-
- // Returns 'true' once ExitCommand has been processed, so the thread can shut down.
- bool IsExiting() const;
-
-
- // These two virtual functions serve as notifications for derived
- // thread waiting.
- virtual void OnPushNonEmpty_Locked() { }
- virtual void OnPopEmpty_Locked() { }
-
-
- // *** PushCall with no result
-
- // Enqueue a member function of 'this' class to be called on consumer thread.
- // By default the function returns immediately; set 'wait' argument to 'true' to
- // wait for completion.
- template<class C, class R>
- bool PushCall(R (C::*fn)(), bool wait = false)
- { return PushCommand(ThreadCommandMF0<C,R>(static_cast<C*>(this), fn, 0, wait)); }
- template<class C, class R, class A0>
- bool PushCall(R (C::*fn)(A0), typename SelfType<A0>::Type a0, bool wait = false)
- { return PushCommand(ThreadCommandMF1<C,R,A0>(static_cast<C*>(this), fn, 0, a0, wait)); }
- template<class C, class R, class A0, class A1>
- bool PushCall(R (C::*fn)(A0, A1),
- typename SelfType<A0>::Type a0, typename SelfType<A1>::Type a1, bool wait = false)
- { return PushCommand(ThreadCommandMF2<C,R,A0,A1>(static_cast<C*>(this), fn, 0, a0, a1, wait)); }
- // Enqueue a specified member function call of class C.
- // By default the function returns immediately; set 'wait' argument to 'true' to
- // wait for completion.
- template<class C, class R>
- bool PushCall(C* p, R (C::*fn)(), bool wait = false)
- { return PushCommand(ThreadCommandMF0<C,R>(p, fn, 0, wait)); }
- template<class C, class R, class A0>
- bool PushCall(C* p, R (C::*fn)(A0), typename SelfType<A0>::Type a0, bool wait = false)
- { return PushCommand(ThreadCommandMF1<C,R,A0>(p, fn, 0, a0, wait)); }
- template<class C, class R, class A0, class A1>
- bool PushCall(C* p, R (C::*fn)(A0, A1),
- typename SelfType<A0>::Type a0, typename SelfType<A1>::Type a1, bool wait = false)
- { return PushCommand(ThreadCommandMF2<C,R,A0,A1>(p, fn, 0, a0, a1, wait)); }
-
-
- // *** PushCall with Result
-
- // Enqueue a member function of 'this' class call and wait for call to complete
- // on consumer thread before returning.
- template<class C, class R>
- bool PushCallAndWaitResult(R (C::*fn)(), R* ret)
- { return PushCommand(ThreadCommandMF0<C,R>(static_cast<C*>(this), fn, ret, true)); }
- template<class C, class R, class A0>
- bool PushCallAndWaitResult(R (C::*fn)(A0), R* ret, typename SelfType<A0>::Type a0)
- { return PushCommand(ThreadCommandMF1<C,R,A0>(static_cast<C*>(this), fn, ret, a0, true)); }
- template<class C, class R, class A0, class A1>
- bool PushCallAndWaitResult(R (C::*fn)(A0, A1), R* ret,
- typename SelfType<A0>::Type a0, typename SelfType<A1>::Type a1)
- { return PushCommand(ThreadCommandMF2<C,R,A0,A1>(static_cast<C*>(this), fn, ret, a0, a1, true)); }
- // Enqueue a member function call for class C and wait for the call to complete
- // on consumer thread before returning.
- template<class C, class R>
- bool PushCallAndWaitResult(C* p, R (C::*fn)(), R* ret)
- { return PushCommand(ThreadCommandMF0<C,R>(p, fn, ret, true)); }
- template<class C, class R, class A0>
- bool PushCallAndWaitResult(C* p, R (C::*fn)(A0), R* ret, typename SelfType<A0>::Type a0)
- { return PushCommand(ThreadCommandMF1<C,R,A0>(p, fn, ret, a0, true)); }
- template<class C, class R, class A0, class A1>
- bool PushCallAndWaitResult(C* p, R (C::*fn)(A0, A1), R* ret,
- typename SelfType<A0>::Type a0, typename SelfType<A1>::Type a1)
- { return PushCommand(ThreadCommandMF2<C,R,A0,A1>(p, fn, ret, a0, a1, true)); }
-
-private:
- class ThreadCommandQueueImpl* pImpl;
-};
-
-
-}
-
-#endif // OVR_ThreadCommandQueue_h
+/************************************************************************************
+
+PublicHeader: None
+Filename : OVR_ThreadCommandQueue.h
+Content : Command queue for operations executed on a thread
+Created : October 29, 2012
+Author : Michael Antonov
+
+Copyright : Copyright 2012 Oculus VR, Inc. All Rights reserved.
+
+Use of this software is subject to the terms of the Oculus license
+agreement provided at the time of installation or download, or which
+otherwise accompanies this software in either electronic or hard copy form.
+
+************************************************************************************/
+
+#ifndef OVR_ThreadCommandQueue_h
+#define OVR_ThreadCommandQueue_h
+
+#include "Kernel/OVR_Types.h"
+#include "Kernel/OVR_List.h"
+#include "Kernel/OVR_Atomic.h"
+#include "Kernel/OVR_Threads.h"
+
+namespace OVR {
+
+class ThreadCommand;
+class ThreadCommandQueue;
+
+
+//-------------------------------------------------------------------------------------
+// ***** ThreadCommand
+
+// ThreadCommand is a base class implementation for commands stored in ThreadCommandQueue.
+class ThreadCommand
+{
+public:
+
+ // NotifyEvent is used by ThreadCommandQueue::PushCallAndWait to notify the
+ // calling (producer) thread when command is completed or queue slot is available.
+ class NotifyEvent : public ListNode<NotifyEvent>, public NewOverrideBase
+ {
+ Event E;
+ public:
+ NotifyEvent() { }
+
+ void Wait() { E.Wait(); }
+ void PulseEvent() { E.PulseEvent(); }
+ };
+
+ // ThreadCommand::PopBuffer is temporary storage for a command popped off
+ // by ThreadCommandQueue::PopCommand.
+ class PopBuffer
+ {
+ enum { MaxSize = 256 };
+
+ UPInt Size;
+ union {
+ UByte Buffer[MaxSize];
+ UPInt Align;
+ };
+
+ ThreadCommand* toCommand() const { return (ThreadCommand*)Buffer; }
+
+ public:
+ PopBuffer() : Size(0) { }
+ ~PopBuffer();
+
+ void InitFromBuffer(void* data);
+
+ bool HasCommand() const { return Size != 0; }
+ UPInt GetSize() const { return Size; }
+ bool NeedsWait() const { return toCommand()->NeedsWait(); }
+ NotifyEvent* GetEvent() const { return toCommand()->pEvent; }
+
+ // Execute the command and also notifies caller to finish waiting,
+ // if necessary.
+ void Execute();
+ };
+
+ UInt16 Size;
+ bool WaitFlag;
+ bool ExitFlag; // Marks the last exit command.
+ NotifyEvent* pEvent;
+
+ ThreadCommand(UPInt size, bool waitFlag, bool exitFlag = false)
+ : Size((UInt16)size), WaitFlag(waitFlag), ExitFlag(exitFlag), pEvent(0) { }
+ virtual ~ThreadCommand() { }
+
+ bool NeedsWait() const { return WaitFlag; }
+ UPInt GetSize() const { return Size; }
+
+ virtual void Execute() const = 0;
+ // Copy constructor used for serializing this to memory buffer.
+ virtual ThreadCommand* CopyConstruct(void* p) const = 0;
+};
+
+
+//-------------------------------------------------------------------------------------
+
+// CleanType is a template that strips 'const' and '&' modifiers from the argument type;
+// for example, typename CleanType<A&>::Type is equivalent to A.
+template<class T> struct CleanType { typedef T Type; };
+template<class T> struct CleanType<T&> { typedef T Type; };
+template<class T> struct CleanType<const T> { typedef T Type; };
+template<class T> struct CleanType<const T&> { typedef T Type; };
+
+// SelfType is a template that yields the argument type. This helps avoid conflicts with
+// automatic template argument deduction for function calls when identical argument
+// is already defined.
+template<class T> struct SelfType { typedef T Type; };
+
+
+
+//-------------------------------------------------------------------------------------
+// ThreadCommand specializations for member functions with different number of
+// arguments and argument types.
+
+// Used to return nothing from a ThreadCommand, to avoid problems with 'void'.
+struct Void
+{
+ Void() {}
+ Void(int) {}
+};
+
+// ThreadCommand for member function with 0 arguments.
+template<class C, class R>
+class ThreadCommandMF0 : public ThreadCommand
+{
+ typedef R (C::*FnPtr)();
+ C* pClass;
+ FnPtr pFn;
+ R* pRet;
+
+ void executeImpl() const
+ {
+ pRet ? (void)(*pRet = (pClass->*pFn)()) :
+ (void)(pClass->*pFn)();
+ }
+
+public:
+ ThreadCommandMF0(C* pclass, FnPtr fn, R* ret, bool needsWait)
+ : ThreadCommand(sizeof(ThreadCommandMF0), needsWait),
+ pClass(pclass), pFn(fn), pRet(ret) { }
+
+ virtual void Execute() const { executeImpl(); }
+ virtual ThreadCommand* CopyConstruct(void* p) const
+ { return Construct<ThreadCommandMF0>(p, *this); }
+};
+
+
+// ThreadCommand for member function with 1 argument.
+template<class C, class R, class A0>
+class ThreadCommandMF1 : public ThreadCommand
+{
+ typedef R (C::*FnPtr)(A0);
+ C* pClass;
+ FnPtr pFn;
+ R* pRet;
+ typename CleanType<A0>::Type AVal0;
+
+ void executeImpl() const
+ {
+ pRet ? (void)(*pRet = (pClass->*pFn)(AVal0)) :
+ (void)(pClass->*pFn)(AVal0);
+ }
+
+public:
+ ThreadCommandMF1(C* pclass, FnPtr fn, R* ret, A0 a0, bool needsWait)
+ : ThreadCommand(sizeof(ThreadCommandMF1), needsWait),
+ pClass(pclass), pFn(fn), pRet(ret), AVal0(a0) { }
+
+ virtual void Execute() const { executeImpl(); }
+ virtual ThreadCommand* CopyConstruct(void* p) const
+ { return Construct<ThreadCommandMF1>(p, *this); }
+};
+
+// ThreadCommand for member function with 2 arguments.
+template<class C, class R, class A0, class A1>
+class ThreadCommandMF2 : public ThreadCommand
+{
+ typedef R (C::*FnPtr)(A0, A1);
+ C* pClass;
+ FnPtr pFn;
+ R* pRet;
+ typename CleanType<A0>::Type AVal0;
+ typename CleanType<A1>::Type AVal1;
+
+ void executeImpl() const
+ {
+ pRet ? (void)(*pRet = (pClass->*pFn)(AVal0, AVal1)) :
+ (void)(pClass->*pFn)(AVal0, AVal1);
+ }
+
+public:
+ ThreadCommandMF2(C* pclass, FnPtr fn, R* ret, A0 a0, A1 a1, bool needsWait)
+ : ThreadCommand(sizeof(ThreadCommandMF2), needsWait),
+ pClass(pclass), pFn(fn), pRet(ret), AVal0(a0), AVal1(a1) { }
+
+ virtual void Execute() const { executeImpl(); }
+ virtual ThreadCommand* CopyConstruct(void* p) const
+ { return Construct<ThreadCommandMF2>(p, *this); }
+};
+
+
+//-------------------------------------------------------------------------------------
+// ***** ThreadCommandQueue
+
+// ThreadCommandQueue is a queue of executable function-call commands intended to be
+// serviced by a single consumer thread. Commands are added to the queue with PushCall
+// and removed with PopCall; they are processed in FIFO order. Multiple producer threads
+// are supported and will be blocked if internal data buffer is full.
+
+class ThreadCommandQueue
+{
+public:
+
+ ThreadCommandQueue();
+ virtual ~ThreadCommandQueue();
+
+
+ // Pops the next command from the thread queue, if any is available.
+ // The command should be executed by calling popBuffer->Execute().
+ // Returns 'false' if no command is available at the time of the call.
+ bool PopCommand(ThreadCommand::PopBuffer* popBuffer);
+
+ // Generic implementaion of PushCommand; enqueues a command for execution.
+ // Returns 'false' if push failed, usually indicating thread shutdown.
+ bool PushCommand(const ThreadCommand& command);
+
+ //
+ void PushExitCommand(bool wait);
+
+ // Returns 'true' once ExitCommand has been processed, so the thread can shut down.
+ bool IsExiting() const;
+
+
+ // These two virtual functions serve as notifications for derived
+ // thread waiting.
+ virtual void OnPushNonEmpty_Locked() { }
+ virtual void OnPopEmpty_Locked() { }
+
+
+ // *** PushCall with no result
+
+ // Enqueue a member function of 'this' class to be called on consumer thread.
+ // By default the function returns immediately; set 'wait' argument to 'true' to
+ // wait for completion.
+ template<class C, class R>
+ bool PushCall(R (C::*fn)(), bool wait = false)
+ { return PushCommand(ThreadCommandMF0<C,R>(static_cast<C*>(this), fn, 0, wait)); }
+ template<class C, class R, class A0>
+ bool PushCall(R (C::*fn)(A0), typename SelfType<A0>::Type a0, bool wait = false)
+ { return PushCommand(ThreadCommandMF1<C,R,A0>(static_cast<C*>(this), fn, 0, a0, wait)); }
+ template<class C, class R, class A0, class A1>
+ bool PushCall(R (C::*fn)(A0, A1),
+ typename SelfType<A0>::Type a0, typename SelfType<A1>::Type a1, bool wait = false)
+ { return PushCommand(ThreadCommandMF2<C,R,A0,A1>(static_cast<C*>(this), fn, 0, a0, a1, wait)); }
+ // Enqueue a specified member function call of class C.
+ // By default the function returns immediately; set 'wait' argument to 'true' to
+ // wait for completion.
+ template<class C, class R>
+ bool PushCall(C* p, R (C::*fn)(), bool wait = false)
+ { return PushCommand(ThreadCommandMF0<C,R>(p, fn, 0, wait)); }
+ template<class C, class R, class A0>
+ bool PushCall(C* p, R (C::*fn)(A0), typename SelfType<A0>::Type a0, bool wait = false)
+ { return PushCommand(ThreadCommandMF1<C,R,A0>(p, fn, 0, a0, wait)); }
+ template<class C, class R, class A0, class A1>
+ bool PushCall(C* p, R (C::*fn)(A0, A1),
+ typename SelfType<A0>::Type a0, typename SelfType<A1>::Type a1, bool wait = false)
+ { return PushCommand(ThreadCommandMF2<C,R,A0,A1>(p, fn, 0, a0, a1, wait)); }
+
+
+ // *** PushCall with Result
+
+ // Enqueue a member function of 'this' class call and wait for call to complete
+ // on consumer thread before returning.
+ template<class C, class R>
+ bool PushCallAndWaitResult(R (C::*fn)(), R* ret)
+ { return PushCommand(ThreadCommandMF0<C,R>(static_cast<C*>(this), fn, ret, true)); }
+ template<class C, class R, class A0>
+ bool PushCallAndWaitResult(R (C::*fn)(A0), R* ret, typename SelfType<A0>::Type a0)
+ { return PushCommand(ThreadCommandMF1<C,R,A0>(static_cast<C*>(this), fn, ret, a0, true)); }
+ template<class C, class R, class A0, class A1>
+ bool PushCallAndWaitResult(R (C::*fn)(A0, A1), R* ret,
+ typename SelfType<A0>::Type a0, typename SelfType<A1>::Type a1)
+ { return PushCommand(ThreadCommandMF2<C,R,A0,A1>(static_cast<C*>(this), fn, ret, a0, a1, true)); }
+ // Enqueue a member function call for class C and wait for the call to complete
+ // on consumer thread before returning.
+ template<class C, class R>
+ bool PushCallAndWaitResult(C* p, R (C::*fn)(), R* ret)
+ { return PushCommand(ThreadCommandMF0<C,R>(p, fn, ret, true)); }
+ template<class C, class R, class A0>
+ bool PushCallAndWaitResult(C* p, R (C::*fn)(A0), R* ret, typename SelfType<A0>::Type a0)
+ { return PushCommand(ThreadCommandMF1<C,R,A0>(p, fn, ret, a0, true)); }
+ template<class C, class R, class A0, class A1>
+ bool PushCallAndWaitResult(C* p, R (C::*fn)(A0, A1), R* ret,
+ typename SelfType<A0>::Type a0, typename SelfType<A1>::Type a1)
+ { return PushCommand(ThreadCommandMF2<C,R,A0,A1>(p, fn, ret, a0, a1, true)); }
+
+private:
+ class ThreadCommandQueueImpl* pImpl;
+};
+
+
+}
+
+#endif // OVR_ThreadCommandQueue_h
diff --git a/LibOVR/Src/OVR_Win32_DeviceManager.cpp b/LibOVR/Src/OVR_Win32_DeviceManager.cpp
index f7bb9eb..eebb924 100644
--- a/LibOVR/Src/OVR_Win32_DeviceManager.cpp
+++ b/LibOVR/Src/OVR_Win32_DeviceManager.cpp
@@ -1,423 +1,423 @@
-/************************************************************************************
-
-Filename : OVR_Win32_DeviceManager.cpp
-Content : Win32 implementation of DeviceManager.
-Created : September 21, 2012
-Authors : Michael Antonov
-
-Copyright : Copyright 2012 Oculus VR, Inc. All Rights reserved.
-
-Use of this software is subject to the terms of the Oculus license
-agreement provided at the time of installation or download, or which
-otherwise accompanies this software in either electronic or hard copy form.
-
-*************************************************************************************/
-
-#include "OVR_Win32_DeviceManager.h"
-
-// Sensor & HMD Factories
-#include "OVR_SensorImpl.h"
-#include "OVR_LatencyTestImpl.h"
-#include "OVR_Win32_HMDDevice.h"
-#include "OVR_Win32_DeviceStatus.h"
-#include "OVR_Win32_HIDDevice.h"
-
-#include "Kernel/OVR_Timer.h"
-#include "Kernel/OVR_Std.h"
-#include "Kernel/OVR_Log.h"
-
-DWORD Debug_WaitedObjectCount = 0;
-
-namespace OVR { namespace Win32 {
-
-
-//-------------------------------------------------------------------------------------
-// **** Win32::DeviceManager
-
-DeviceManager::DeviceManager()
-{
- HidDeviceManager = *HIDDeviceManager::CreateInternal(this);
-}
-
-DeviceManager::~DeviceManager()
-{
- // make sure Shutdown was called.
- OVR_ASSERT(!pThread);
-}
-
-bool DeviceManager::Initialize(DeviceBase*)
-{
- if (!DeviceManagerImpl::Initialize(0))
- return false;
-
- pThread = *new DeviceManagerThread(this);
- if (!pThread || !pThread->Start())
- return false;
-
- pCreateDesc->pDevice = this;
- LogText("OVR::DeviceManager - initialized.\n");
- return true;
-}
-
-void DeviceManager::Shutdown()
-{
- LogText("OVR::DeviceManager - shutting down.\n");
-
- // Set Manager shutdown marker variable; this prevents
- // any existing DeviceHandle objects from accessing device.
- pCreateDesc->pLock->pManager = 0;
-
- // Push for thread shutdown *WITH NO WAIT*.
- // This will have the following effect:
- // - Exit command will get enqueued, which will be executed later on the thread itself.
- // - Beyond this point, this DeviceManager object may be deleted by our caller.
- // - Other commands, such as CreateDevice, may execute before ExitCommand, but they will
- // fail gracefully due to pLock->pManager == 0. Future commands can't be enqued
- // after pManager is null.
- // - Once ExitCommand executes, ThreadCommand::Run loop will exit and release the last
- // reference to the thread object.
- pThread->PushExitCommand(false);
- pThread->DetachDeviceManager();
- pThread.Clear();
-
- DeviceManagerImpl::Shutdown();
-}
-
-ThreadCommandQueue* DeviceManager::GetThreadQueue()
-{
- return pThread;
-}
-
-bool DeviceManager::GetDeviceInfo(DeviceInfo* info) const
-{
- if ((info->InfoClassType != Device_Manager) &&
- (info->InfoClassType != Device_None))
- return false;
-
- info->Type = Device_Manager;
- info->Version = 0;
- OVR_strcpy(info->ProductName, DeviceInfo::MaxNameLength, "DeviceManager");
- OVR_strcpy(info->Manufacturer,DeviceInfo::MaxNameLength, "Oculus VR, Inc.");
- return true;
-}
-
-DeviceEnumerator<> DeviceManager::EnumerateDevicesEx(const DeviceEnumerationArgs& args)
-{
- // TBD: Can this be avoided in the future, once proper device notification is in place?
- if (GetThreadId() != OVR::GetCurrentThreadId())
- {
- pThread->PushCall((DeviceManagerImpl*)this,
- &DeviceManager::EnumerateAllFactoryDevices, true);
- }
- else
- DeviceManager::EnumerateAllFactoryDevices();
-
- return DeviceManagerImpl::EnumerateDevicesEx(args);
-}
-
-ThreadId DeviceManager::GetThreadId() const
-{
- return pThread->GetThreadId();
-}
-
-bool DeviceManager::GetHIDDeviceDesc(const String& path, HIDDeviceDesc* pdevDesc) const
-{
- if (GetHIDDeviceManager())
- return static_cast<HIDDeviceManager*>(GetHIDDeviceManager())->GetHIDDeviceDesc(path, pdevDesc);
- return false;
-}
-
-
-//-------------------------------------------------------------------------------------
-// ***** DeviceManager Thread
-
-DeviceManagerThread::DeviceManagerThread(DeviceManager* pdevMgr)
- : Thread(ThreadStackSize), hCommandEvent(0), pDeviceMgr(pdevMgr)
-{
- // Create a non-signaled manual-reset event.
- hCommandEvent = ::CreateEvent(0, TRUE, FALSE, 0);
- if (!hCommandEvent)
- return;
-
- // Must add event before starting.
- AddOverlappedEvent(0, hCommandEvent);
-
- // Create device messages object.
- pStatusObject = *new DeviceStatus(this);
-}
-
-DeviceManagerThread::~DeviceManagerThread()
-{
- // Remove overlapped event [0], after thread service exit.
- if (hCommandEvent)
- {
- RemoveOverlappedEvent(0, hCommandEvent);
- ::CloseHandle(hCommandEvent);
- hCommandEvent = 0;
- }
-}
-
-int DeviceManagerThread::Run()
-{
- ThreadCommand::PopBuffer command;
-
- SetThreadName("OVR::DeviceManagerThread");
- LogText("OVR::DeviceManagerThread - running (ThreadId=0x%X).\n", GetThreadId());
-
- if (!pStatusObject->Initialize())
- {
- LogText("OVR::DeviceManagerThread - failed to initialize MessageObject.\n");
- }
-
- while(!IsExiting())
- {
- // PopCommand will reset event on empty queue.
- if (PopCommand(&command))
- {
- command.Execute();
- }
- else
- {
- DWORD eventIndex = 0;
- do {
- UPInt numberOfWaitHandles = WaitHandles.GetSize();
- Debug_WaitedObjectCount = (DWORD)numberOfWaitHandles;
-
- DWORD waitMs = INFINITE;
-
- // If devices have time-dependent logic registered, get the longest wait
- // allowed based on current ticks.
- if (!TicksNotifiers.IsEmpty())
- {
- UInt64 ticksMks = Timer::GetTicks();
- DWORD waitAllowed;
-
- for (UPInt j = 0; j < TicksNotifiers.GetSize(); j++)
- {
- waitAllowed = (DWORD)(TicksNotifiers[j]->OnTicks(ticksMks) / Timer::MksPerMs);
- if (waitAllowed < waitMs)
- waitMs = waitAllowed;
- }
- }
-
- // Wait for event signals or window messages.
- eventIndex = MsgWaitForMultipleObjects((DWORD)numberOfWaitHandles, &WaitHandles[0], FALSE, waitMs, QS_ALLINPUT);
-
- if (eventIndex != WAIT_FAILED)
- {
- if (eventIndex == WAIT_TIMEOUT)
- continue;
-
- // TBD: Does this ever apply?
- OVR_ASSERT(eventIndex < WAIT_ABANDONED_0);
-
- if (eventIndex == WAIT_OBJECT_0)
- {
- // Handle [0] services commands.
- break;
- }
- else if (eventIndex == WAIT_OBJECT_0 + numberOfWaitHandles)
- {
- // Handle Windows messages.
- pStatusObject->ProcessMessages();
- }
- else
- {
- // Notify waiting device that its event is signaled.
- unsigned i = eventIndex - WAIT_OBJECT_0;
- OVR_ASSERT(i < numberOfWaitHandles);
- if (WaitNotifiers[i])
- WaitNotifiers[i]->OnOverlappedEvent(WaitHandles[i]);
- }
- }
-
- } while(eventIndex != WAIT_FAILED);
-
- }
- }
-
- pStatusObject->ShutDown();
-
- LogText("OVR::DeviceManagerThread - exiting (ThreadId=0x%X).\n", GetThreadId());
- return 0;
-}
-
-bool DeviceManagerThread::AddOverlappedEvent(Notifier* notify, HANDLE hevent)
-{
- WaitNotifiers.PushBack(notify);
- WaitHandles.PushBack(hevent);
-
- OVR_ASSERT(WaitNotifiers.GetSize() <= MAXIMUM_WAIT_OBJECTS);
- return true;
-}
-
-bool DeviceManagerThread::RemoveOverlappedEvent(Notifier* notify, HANDLE hevent)
-{
- // [0] is reserved for thread commands with notify of null, but we still
- // can use this function to remove it.
- for (UPInt i = 0; i < WaitNotifiers.GetSize(); i++)
- {
- if ((WaitNotifiers[i] == notify) && (WaitHandles[i] == hevent))
- {
- WaitNotifiers.RemoveAt(i);
- WaitHandles.RemoveAt(i);
- return true;
- }
- }
- return false;
-}
-
-bool DeviceManagerThread::AddTicksNotifier(Notifier* notify)
-{
- TicksNotifiers.PushBack(notify);
- return true;
-}
-
-bool DeviceManagerThread::RemoveTicksNotifier(Notifier* notify)
-{
- for (UPInt i = 0; i < TicksNotifiers.GetSize(); i++)
- {
- if (TicksNotifiers[i] == notify)
- {
- TicksNotifiers.RemoveAt(i);
- return true;
- }
- }
- return false;
-}
-
-bool DeviceManagerThread::AddMessageNotifier(Notifier* notify)
-{
- MessageNotifiers.PushBack(notify);
- return true;
-}
-
-bool DeviceManagerThread::RemoveMessageNotifier(Notifier* notify)
-{
- for (UPInt i = 0; i < MessageNotifiers.GetSize(); i++)
- {
- if (MessageNotifiers[i] == notify)
- {
- MessageNotifiers.RemoveAt(i);
- return true;
- }
- }
- return false;
-}
-
-bool DeviceManagerThread::OnMessage(MessageType type, const String& devicePath)
-{
- Notifier::DeviceMessageType notifierMessageType = Notifier::DeviceMessage_DeviceAdded;
- if (type == DeviceAdded)
- {
- }
- else if (type == DeviceRemoved)
- {
- notifierMessageType = Notifier::DeviceMessage_DeviceRemoved;
- }
- else
- {
- OVR_ASSERT(false);
- }
-
- bool error = false;
- bool deviceFound = false;
- for (UPInt i = 0; i < MessageNotifiers.GetSize(); i++)
- {
- if (MessageNotifiers[i] &&
- MessageNotifiers[i]->OnDeviceMessage(notifierMessageType, devicePath, &error))
- {
- // The notifier belonged to a device with the specified device name so we're done.
- deviceFound = true;
- break;
- }
- }
- if (type == DeviceAdded && !deviceFound)
- {
- Lock::Locker devMgrLock(&DevMgrLock);
- // a new device was connected. Go through all device factories and
- // try to detect the device using HIDDeviceDesc.
- HIDDeviceDesc devDesc;
- if (pDeviceMgr->GetHIDDeviceDesc(devicePath, &devDesc))
- {
- Lock::Locker deviceLock(pDeviceMgr->GetLock());
- DeviceFactory* factory = pDeviceMgr->Factories.GetFirst();
- while(!pDeviceMgr->Factories.IsNull(factory))
- {
- if (factory->DetectHIDDevice(pDeviceMgr, devDesc))
- {
- deviceFound = true;
- break;
- }
- factory = factory->pNext;
- }
- }
- }
-
- if (!deviceFound && strstr(devicePath.ToCStr(), "#OVR00"))
- {
- Ptr<DeviceManager> pmgr;
- {
- Lock::Locker devMgrLock(&DevMgrLock);
- pmgr = pDeviceMgr;
- }
- // HMD plugged/unplugged
- // This is not a final solution to enumerate HMD devices and get
- // a first available handle. This won't work with multiple rifts.
- // @TODO (!AB)
- pmgr->EnumerateDevices<HMDDevice>();
- }
-
- return !error;
-}
-
-void DeviceManagerThread::DetachDeviceManager()
-{
- Lock::Locker devMgrLock(&DevMgrLock);
- pDeviceMgr = NULL;
-}
-
-} // namespace Win32
-
-
-//-------------------------------------------------------------------------------------
-// ***** Creation
-
-
-// Creates a new DeviceManager and initializes OVR.
-DeviceManager* DeviceManager::Create()
-{
-
- if (!System::IsInitialized())
- {
- // Use custom message, since Log is not yet installed.
- OVR_DEBUG_STATEMENT(Log::GetDefaultLog()->
- LogMessage(Log_Debug, "DeviceManager::Create failed - OVR::System not initialized"); );
- return 0;
- }
-
- Ptr<Win32::DeviceManager> manager = *new Win32::DeviceManager;
-
- if (manager)
- {
- if (manager->Initialize(0))
- {
- manager->AddFactory(&SensorDeviceFactory::Instance);
- manager->AddFactory(&LatencyTestDeviceFactory::Instance);
- manager->AddFactory(&Win32::HMDDeviceFactory::Instance);
-
- manager->AddRef();
- }
- else
- {
- manager.Clear();
- }
-
- }
-
- return manager.GetPtr();
-}
-
-
-} // namespace OVR
-
+/************************************************************************************
+
+Filename : OVR_Win32_DeviceManager.cpp
+Content : Win32 implementation of DeviceManager.
+Created : September 21, 2012
+Authors : Michael Antonov
+
+Copyright : Copyright 2012 Oculus VR, Inc. All Rights reserved.
+
+Use of this software is subject to the terms of the Oculus license
+agreement provided at the time of installation or download, or which
+otherwise accompanies this software in either electronic or hard copy form.
+
+*************************************************************************************/
+
+#include "OVR_Win32_DeviceManager.h"
+
+// Sensor & HMD Factories
+#include "OVR_SensorImpl.h"
+#include "OVR_LatencyTestImpl.h"
+#include "OVR_Win32_HMDDevice.h"
+#include "OVR_Win32_DeviceStatus.h"
+#include "OVR_Win32_HIDDevice.h"
+
+#include "Kernel/OVR_Timer.h"
+#include "Kernel/OVR_Std.h"
+#include "Kernel/OVR_Log.h"
+
+DWORD Debug_WaitedObjectCount = 0;
+
+namespace OVR { namespace Win32 {
+
+
+//-------------------------------------------------------------------------------------
+// **** Win32::DeviceManager
+
+DeviceManager::DeviceManager()
+{
+ HidDeviceManager = *HIDDeviceManager::CreateInternal(this);
+}
+
+DeviceManager::~DeviceManager()
+{
+ // make sure Shutdown was called.
+ OVR_ASSERT(!pThread);
+}
+
+bool DeviceManager::Initialize(DeviceBase*)
+{
+ if (!DeviceManagerImpl::Initialize(0))
+ return false;
+
+ pThread = *new DeviceManagerThread(this);
+ if (!pThread || !pThread->Start())
+ return false;
+
+ pCreateDesc->pDevice = this;
+ LogText("OVR::DeviceManager - initialized.\n");
+ return true;
+}
+
+void DeviceManager::Shutdown()
+{
+ LogText("OVR::DeviceManager - shutting down.\n");
+
+ // Set Manager shutdown marker variable; this prevents
+ // any existing DeviceHandle objects from accessing device.
+ pCreateDesc->pLock->pManager = 0;
+
+ // Push for thread shutdown *WITH NO WAIT*.
+ // This will have the following effect:
+ // - Exit command will get enqueued, which will be executed later on the thread itself.
+ // - Beyond this point, this DeviceManager object may be deleted by our caller.
+ // - Other commands, such as CreateDevice, may execute before ExitCommand, but they will
+ // fail gracefully due to pLock->pManager == 0. Future commands can't be enqued
+ // after pManager is null.
+ // - Once ExitCommand executes, ThreadCommand::Run loop will exit and release the last
+ // reference to the thread object.
+ pThread->PushExitCommand(false);
+ pThread->DetachDeviceManager();
+ pThread.Clear();
+
+ DeviceManagerImpl::Shutdown();
+}
+
+ThreadCommandQueue* DeviceManager::GetThreadQueue()
+{
+ return pThread;
+}
+
+bool DeviceManager::GetDeviceInfo(DeviceInfo* info) const
+{
+ if ((info->InfoClassType != Device_Manager) &&
+ (info->InfoClassType != Device_None))
+ return false;
+
+ info->Type = Device_Manager;
+ info->Version = 0;
+ OVR_strcpy(info->ProductName, DeviceInfo::MaxNameLength, "DeviceManager");
+ OVR_strcpy(info->Manufacturer,DeviceInfo::MaxNameLength, "Oculus VR, Inc.");
+ return true;
+}
+
+DeviceEnumerator<> DeviceManager::EnumerateDevicesEx(const DeviceEnumerationArgs& args)
+{
+ // TBD: Can this be avoided in the future, once proper device notification is in place?
+ if (GetThreadId() != OVR::GetCurrentThreadId())
+ {
+ pThread->PushCall((DeviceManagerImpl*)this,
+ &DeviceManager::EnumerateAllFactoryDevices, true);
+ }
+ else
+ DeviceManager::EnumerateAllFactoryDevices();
+
+ return DeviceManagerImpl::EnumerateDevicesEx(args);
+}
+
+ThreadId DeviceManager::GetThreadId() const
+{
+ return pThread->GetThreadId();
+}
+
+bool DeviceManager::GetHIDDeviceDesc(const String& path, HIDDeviceDesc* pdevDesc) const
+{
+ if (GetHIDDeviceManager())
+ return static_cast<HIDDeviceManager*>(GetHIDDeviceManager())->GetHIDDeviceDesc(path, pdevDesc);
+ return false;
+}
+
+
+//-------------------------------------------------------------------------------------
+// ***** DeviceManager Thread
+
+DeviceManagerThread::DeviceManagerThread(DeviceManager* pdevMgr)
+ : Thread(ThreadStackSize), hCommandEvent(0), pDeviceMgr(pdevMgr)
+{
+ // Create a non-signaled manual-reset event.
+ hCommandEvent = ::CreateEvent(0, TRUE, FALSE, 0);
+ if (!hCommandEvent)
+ return;
+
+ // Must add event before starting.
+ AddOverlappedEvent(0, hCommandEvent);
+
+ // Create device messages object.
+ pStatusObject = *new DeviceStatus(this);
+}
+
+DeviceManagerThread::~DeviceManagerThread()
+{
+ // Remove overlapped event [0], after thread service exit.
+ if (hCommandEvent)
+ {
+ RemoveOverlappedEvent(0, hCommandEvent);
+ ::CloseHandle(hCommandEvent);
+ hCommandEvent = 0;
+ }
+}
+
+int DeviceManagerThread::Run()
+{
+ ThreadCommand::PopBuffer command;
+
+ SetThreadName("OVR::DeviceManagerThread");
+ LogText("OVR::DeviceManagerThread - running (ThreadId=0x%X).\n", GetThreadId());
+
+ if (!pStatusObject->Initialize())
+ {
+ LogText("OVR::DeviceManagerThread - failed to initialize MessageObject.\n");
+ }
+
+ while(!IsExiting())
+ {
+ // PopCommand will reset event on empty queue.
+ if (PopCommand(&command))
+ {
+ command.Execute();
+ }
+ else
+ {
+ DWORD eventIndex = 0;
+ do {
+ UPInt numberOfWaitHandles = WaitHandles.GetSize();
+ Debug_WaitedObjectCount = (DWORD)numberOfWaitHandles;
+
+ DWORD waitMs = INFINITE;
+
+ // If devices have time-dependent logic registered, get the longest wait
+ // allowed based on current ticks.
+ if (!TicksNotifiers.IsEmpty())
+ {
+ UInt64 ticksMks = Timer::GetTicks();
+ DWORD waitAllowed;
+
+ for (UPInt j = 0; j < TicksNotifiers.GetSize(); j++)
+ {
+ waitAllowed = (DWORD)(TicksNotifiers[j]->OnTicks(ticksMks) / Timer::MksPerMs);
+ if (waitAllowed < waitMs)
+ waitMs = waitAllowed;
+ }
+ }
+
+ // Wait for event signals or window messages.
+ eventIndex = MsgWaitForMultipleObjects((DWORD)numberOfWaitHandles, &WaitHandles[0], FALSE, waitMs, QS_ALLINPUT);
+
+ if (eventIndex != WAIT_FAILED)
+ {
+ if (eventIndex == WAIT_TIMEOUT)
+ continue;
+
+ // TBD: Does this ever apply?
+ OVR_ASSERT(eventIndex < WAIT_ABANDONED_0);
+
+ if (eventIndex == WAIT_OBJECT_0)
+ {
+ // Handle [0] services commands.
+ break;
+ }
+ else if (eventIndex == WAIT_OBJECT_0 + numberOfWaitHandles)
+ {
+ // Handle Windows messages.
+ pStatusObject->ProcessMessages();
+ }
+ else
+ {
+ // Notify waiting device that its event is signaled.
+ unsigned i = eventIndex - WAIT_OBJECT_0;
+ OVR_ASSERT(i < numberOfWaitHandles);
+ if (WaitNotifiers[i])
+ WaitNotifiers[i]->OnOverlappedEvent(WaitHandles[i]);
+ }
+ }
+
+ } while(eventIndex != WAIT_FAILED);
+
+ }
+ }
+
+ pStatusObject->ShutDown();
+
+ LogText("OVR::DeviceManagerThread - exiting (ThreadId=0x%X).\n", GetThreadId());
+ return 0;
+}
+
+bool DeviceManagerThread::AddOverlappedEvent(Notifier* notify, HANDLE hevent)
+{
+ WaitNotifiers.PushBack(notify);
+ WaitHandles.PushBack(hevent);
+
+ OVR_ASSERT(WaitNotifiers.GetSize() <= MAXIMUM_WAIT_OBJECTS);
+ return true;
+}
+
+bool DeviceManagerThread::RemoveOverlappedEvent(Notifier* notify, HANDLE hevent)
+{
+ // [0] is reserved for thread commands with notify of null, but we still
+ // can use this function to remove it.
+ for (UPInt i = 0; i < WaitNotifiers.GetSize(); i++)
+ {
+ if ((WaitNotifiers[i] == notify) && (WaitHandles[i] == hevent))
+ {
+ WaitNotifiers.RemoveAt(i);
+ WaitHandles.RemoveAt(i);
+ return true;
+ }
+ }
+ return false;
+}
+
+bool DeviceManagerThread::AddTicksNotifier(Notifier* notify)
+{
+ TicksNotifiers.PushBack(notify);
+ return true;
+}
+
+bool DeviceManagerThread::RemoveTicksNotifier(Notifier* notify)
+{
+ for (UPInt i = 0; i < TicksNotifiers.GetSize(); i++)
+ {
+ if (TicksNotifiers[i] == notify)
+ {
+ TicksNotifiers.RemoveAt(i);
+ return true;
+ }
+ }
+ return false;
+}
+
+bool DeviceManagerThread::AddMessageNotifier(Notifier* notify)
+{
+ MessageNotifiers.PushBack(notify);
+ return true;
+}
+
+bool DeviceManagerThread::RemoveMessageNotifier(Notifier* notify)
+{
+ for (UPInt i = 0; i < MessageNotifiers.GetSize(); i++)
+ {
+ if (MessageNotifiers[i] == notify)
+ {
+ MessageNotifiers.RemoveAt(i);
+ return true;
+ }
+ }
+ return false;
+}
+
+bool DeviceManagerThread::OnMessage(MessageType type, const String& devicePath)
+{
+ Notifier::DeviceMessageType notifierMessageType = Notifier::DeviceMessage_DeviceAdded;
+ if (type == DeviceAdded)
+ {
+ }
+ else if (type == DeviceRemoved)
+ {
+ notifierMessageType = Notifier::DeviceMessage_DeviceRemoved;
+ }
+ else
+ {
+ OVR_ASSERT(false);
+ }
+
+ bool error = false;
+ bool deviceFound = false;
+ for (UPInt i = 0; i < MessageNotifiers.GetSize(); i++)
+ {
+ if (MessageNotifiers[i] &&
+ MessageNotifiers[i]->OnDeviceMessage(notifierMessageType, devicePath, &error))
+ {
+ // The notifier belonged to a device with the specified device name so we're done.
+ deviceFound = true;
+ break;
+ }
+ }
+ if (type == DeviceAdded && !deviceFound)
+ {
+ Lock::Locker devMgrLock(&DevMgrLock);
+ // a new device was connected. Go through all device factories and
+ // try to detect the device using HIDDeviceDesc.
+ HIDDeviceDesc devDesc;
+ if (pDeviceMgr->GetHIDDeviceDesc(devicePath, &devDesc))
+ {
+ Lock::Locker deviceLock(pDeviceMgr->GetLock());
+ DeviceFactory* factory = pDeviceMgr->Factories.GetFirst();
+ while(!pDeviceMgr->Factories.IsNull(factory))
+ {
+ if (factory->DetectHIDDevice(pDeviceMgr, devDesc))
+ {
+ deviceFound = true;
+ break;
+ }
+ factory = factory->pNext;
+ }
+ }
+ }
+
+ if (!deviceFound && strstr(devicePath.ToCStr(), "#OVR00"))
+ {
+ Ptr<DeviceManager> pmgr;
+ {
+ Lock::Locker devMgrLock(&DevMgrLock);
+ pmgr = pDeviceMgr;
+ }
+ // HMD plugged/unplugged
+ // This is not a final solution to enumerate HMD devices and get
+ // a first available handle. This won't work with multiple rifts.
+ // @TODO (!AB)
+ pmgr->EnumerateDevices<HMDDevice>();
+ }
+
+ return !error;
+}
+
+void DeviceManagerThread::DetachDeviceManager()
+{
+ Lock::Locker devMgrLock(&DevMgrLock);
+ pDeviceMgr = NULL;
+}
+
+} // namespace Win32
+
+
+//-------------------------------------------------------------------------------------
+// ***** Creation
+
+
+// Creates a new DeviceManager and initializes OVR.
+DeviceManager* DeviceManager::Create()
+{
+
+ if (!System::IsInitialized())
+ {
+ // Use custom message, since Log is not yet installed.
+ OVR_DEBUG_STATEMENT(Log::GetDefaultLog()->
+ LogMessage(Log_Debug, "DeviceManager::Create failed - OVR::System not initialized"); );
+ return 0;
+ }
+
+ Ptr<Win32::DeviceManager> manager = *new Win32::DeviceManager;
+
+ if (manager)
+ {
+ if (manager->Initialize(0))
+ {
+ manager->AddFactory(&SensorDeviceFactory::Instance);
+ manager->AddFactory(&LatencyTestDeviceFactory::Instance);
+ manager->AddFactory(&Win32::HMDDeviceFactory::Instance);
+
+ manager->AddRef();
+ }
+ else
+ {
+ manager.Clear();
+ }
+
+ }
+
+ return manager.GetPtr();
+}
+
+
+} // namespace OVR
+
diff --git a/LibOVR/Src/OVR_Win32_DeviceManager.h b/LibOVR/Src/OVR_Win32_DeviceManager.h
index 3b86c67..1b88657 100644
--- a/LibOVR/Src/OVR_Win32_DeviceManager.h
+++ b/LibOVR/Src/OVR_Win32_DeviceManager.h
@@ -1,146 +1,146 @@
-/************************************************************************************
-
-Filename : OVR_Win32_DeviceManager.h
-Content : Win32-specific DeviceManager header.
-Created : September 21, 2012
-Authors : Michael Antonov
-
-Copyright : Copyright 2012 Oculus VR, Inc. All Rights reserved.
-
-Use of this software is subject to the terms of the Oculus license
-agreement provided at the time of installation or download, or which
-otherwise accompanies this software in either electronic or hard copy form.
-
-*************************************************************************************/
-
-#ifndef OVR_Win32_DeviceManager_h
-#define OVR_Win32_DeviceManager_h
-
-#include "OVR_DeviceImpl.h"
-#include "OVR_Win32_DeviceStatus.h"
-
-#include "Kernel/OVR_Timer.h"
-
-
-namespace OVR { namespace Win32 {
-
-class DeviceManagerThread;
-
-//-------------------------------------------------------------------------------------
-// ***** Win32 DeviceManager
-
-class DeviceManager : public DeviceManagerImpl
-{
-public:
- DeviceManager();
- ~DeviceManager();
-
- // Initialize/Shutdowncreate and shutdown manger thread.
- virtual bool Initialize(DeviceBase* parent);
- virtual void Shutdown();
-
- virtual ThreadCommandQueue* GetThreadQueue();
- virtual ThreadId GetThreadId() const;
-
- virtual DeviceEnumerator<> EnumerateDevicesEx(const DeviceEnumerationArgs& args);
-
- virtual bool GetDeviceInfo(DeviceInfo* info) const;
-
- // Fills HIDDeviceDesc by using the path.
- // Returns 'true' if successful, 'false' otherwise.
- bool GetHIDDeviceDesc(const String& path, HIDDeviceDesc* pdevDesc) const;
-
- Ptr<DeviceManagerThread> pThread;
-};
-
-//-------------------------------------------------------------------------------------
-// ***** Device Manager Background Thread
-
-class DeviceManagerThread : public Thread, public ThreadCommandQueue, public DeviceStatus::Notifier
-{
- friend class DeviceManager;
- enum { ThreadStackSize = 32 * 1024 };
-public:
- DeviceManagerThread(DeviceManager* pdevMgr);
- ~DeviceManagerThread();
-
- virtual int Run();
-
- // ThreadCommandQueue notifications for CommandEvent handling.
- virtual void OnPushNonEmpty_Locked() { ::SetEvent(hCommandEvent); }
- virtual void OnPopEmpty_Locked() { ::ResetEvent(hCommandEvent); }
-
-
- // Notifier used for different updates (EVENT or regular timing or messages).
- class Notifier
- {
- public:
- // Called when overlapped I/O handle is signaled.
- virtual void OnOverlappedEvent(HANDLE hevent) { OVR_UNUSED1(hevent); }
-
- // Called when timing ticks are updated.
- // Returns the largest number of microseconds this function can
- // wait till next call.
- virtual UInt64 OnTicks(UInt64 ticksMks)
- { OVR_UNUSED1(ticksMks); return Timer::MksPerSecond * 1000; }
-
- enum DeviceMessageType
- {
- DeviceMessage_DeviceAdded = 0,
- DeviceMessage_DeviceRemoved = 1,
- };
-
- // Called to notify device object.
- virtual bool OnDeviceMessage(DeviceMessageType messageType,
- const String& devicePath,
- bool* error)
- { OVR_UNUSED3(messageType, devicePath, error); return false; }
- };
-
-
- // Adds device's OVERLAPPED structure for I/O.
- // After it's added, Overlapped object will be signaled if a message arrives.
- bool AddOverlappedEvent(Notifier* notify, HANDLE hevent);
- bool RemoveOverlappedEvent(Notifier* notify, HANDLE hevent);
-
- // Add notifier that will be called at regular intervals.
- bool AddTicksNotifier(Notifier* notify);
- bool RemoveTicksNotifier(Notifier* notify);
-
- bool AddMessageNotifier(Notifier* notify);
- bool RemoveMessageNotifier(Notifier* notify);
-
- // DeviceStatus::Notifier interface.
- bool OnMessage(MessageType type, const String& devicePath);
-
- void DetachDeviceManager();
-
-private:
- bool threadInitialized() { return hCommandEvent != 0; }
-
- // Event used to wake us up thread commands are enqueued.
- HANDLE hCommandEvent;
-
- // Event notifications for devices whose OVERLAPPED I/O we service.
- // This list is modified through AddDeviceOverlappedEvent.
- // WaitHandles[0] always == hCommandEvent, with null device.
- Array<HANDLE> WaitHandles;
- Array<Notifier*> WaitNotifiers;
-
- // Ticks notifiers - used for time-dependent events such as keep-alive.
- Array<Notifier*> TicksNotifiers;
-
- // Message notifiers.
- Array<Notifier*> MessageNotifiers;
-
- // Object that manages notifications originating from Windows messages.
- Ptr<DeviceStatus> pStatusObject;
-
- Lock DevMgrLock;
- // pDeviceMgr should be accessed under DevMgrLock
- DeviceManager* pDeviceMgr; // back ptr, no addref.
-};
-
-}} // namespace Win32::OVR
-
-#endif // OVR_Win32_DeviceManager_h
+/************************************************************************************
+
+Filename : OVR_Win32_DeviceManager.h
+Content : Win32-specific DeviceManager header.
+Created : September 21, 2012
+Authors : Michael Antonov
+
+Copyright : Copyright 2012 Oculus VR, Inc. All Rights reserved.
+
+Use of this software is subject to the terms of the Oculus license
+agreement provided at the time of installation or download, or which
+otherwise accompanies this software in either electronic or hard copy form.
+
+*************************************************************************************/
+
+#ifndef OVR_Win32_DeviceManager_h
+#define OVR_Win32_DeviceManager_h
+
+#include "OVR_DeviceImpl.h"
+#include "OVR_Win32_DeviceStatus.h"
+
+#include "Kernel/OVR_Timer.h"
+
+
+namespace OVR { namespace Win32 {
+
+class DeviceManagerThread;
+
+//-------------------------------------------------------------------------------------
+// ***** Win32 DeviceManager
+
+class DeviceManager : public DeviceManagerImpl
+{
+public:
+ DeviceManager();
+ ~DeviceManager();
+
+ // Initialize/Shutdowncreate and shutdown manger thread.
+ virtual bool Initialize(DeviceBase* parent);
+ virtual void Shutdown();
+
+ virtual ThreadCommandQueue* GetThreadQueue();
+ virtual ThreadId GetThreadId() const;
+
+ virtual DeviceEnumerator<> EnumerateDevicesEx(const DeviceEnumerationArgs& args);
+
+ virtual bool GetDeviceInfo(DeviceInfo* info) const;
+
+ // Fills HIDDeviceDesc by using the path.
+ // Returns 'true' if successful, 'false' otherwise.
+ bool GetHIDDeviceDesc(const String& path, HIDDeviceDesc* pdevDesc) const;
+
+ Ptr<DeviceManagerThread> pThread;
+};
+
+//-------------------------------------------------------------------------------------
+// ***** Device Manager Background Thread
+
+class DeviceManagerThread : public Thread, public ThreadCommandQueue, public DeviceStatus::Notifier
+{
+ friend class DeviceManager;
+ enum { ThreadStackSize = 32 * 1024 };
+public:
+ DeviceManagerThread(DeviceManager* pdevMgr);
+ ~DeviceManagerThread();
+
+ virtual int Run();
+
+ // ThreadCommandQueue notifications for CommandEvent handling.
+ virtual void OnPushNonEmpty_Locked() { ::SetEvent(hCommandEvent); }
+ virtual void OnPopEmpty_Locked() { ::ResetEvent(hCommandEvent); }
+
+
+ // Notifier used for different updates (EVENT or regular timing or messages).
+ class Notifier
+ {
+ public:
+ // Called when overlapped I/O handle is signaled.
+ virtual void OnOverlappedEvent(HANDLE hevent) { OVR_UNUSED1(hevent); }
+
+ // Called when timing ticks are updated.
+ // Returns the largest number of microseconds this function can
+ // wait till next call.
+ virtual UInt64 OnTicks(UInt64 ticksMks)
+ { OVR_UNUSED1(ticksMks); return Timer::MksPerSecond * 1000; }
+
+ enum DeviceMessageType
+ {
+ DeviceMessage_DeviceAdded = 0,
+ DeviceMessage_DeviceRemoved = 1,
+ };
+
+ // Called to notify device object.
+ virtual bool OnDeviceMessage(DeviceMessageType messageType,
+ const String& devicePath,
+ bool* error)
+ { OVR_UNUSED3(messageType, devicePath, error); return false; }
+ };
+
+
+ // Adds device's OVERLAPPED structure for I/O.
+ // After it's added, Overlapped object will be signaled if a message arrives.
+ bool AddOverlappedEvent(Notifier* notify, HANDLE hevent);
+ bool RemoveOverlappedEvent(Notifier* notify, HANDLE hevent);
+
+ // Add notifier that will be called at regular intervals.
+ bool AddTicksNotifier(Notifier* notify);
+ bool RemoveTicksNotifier(Notifier* notify);
+
+ bool AddMessageNotifier(Notifier* notify);
+ bool RemoveMessageNotifier(Notifier* notify);
+
+ // DeviceStatus::Notifier interface.
+ bool OnMessage(MessageType type, const String& devicePath);
+
+ void DetachDeviceManager();
+
+private:
+ bool threadInitialized() { return hCommandEvent != 0; }
+
+ // Event used to wake us up thread commands are enqueued.
+ HANDLE hCommandEvent;
+
+ // Event notifications for devices whose OVERLAPPED I/O we service.
+ // This list is modified through AddDeviceOverlappedEvent.
+ // WaitHandles[0] always == hCommandEvent, with null device.
+ Array<HANDLE> WaitHandles;
+ Array<Notifier*> WaitNotifiers;
+
+ // Ticks notifiers - used for time-dependent events such as keep-alive.
+ Array<Notifier*> TicksNotifiers;
+
+ // Message notifiers.
+ Array<Notifier*> MessageNotifiers;
+
+ // Object that manages notifications originating from Windows messages.
+ Ptr<DeviceStatus> pStatusObject;
+
+ Lock DevMgrLock;
+ // pDeviceMgr should be accessed under DevMgrLock
+ DeviceManager* pDeviceMgr; // back ptr, no addref.
+};
+
+}} // namespace Win32::OVR
+
+#endif // OVR_Win32_DeviceManager_h
diff --git a/LibOVR/Src/OVR_Win32_DeviceStatus.cpp b/LibOVR/Src/OVR_Win32_DeviceStatus.cpp
index 80ec4f9..89e2601 100644
--- a/LibOVR/Src/OVR_Win32_DeviceStatus.cpp
+++ b/LibOVR/Src/OVR_Win32_DeviceStatus.cpp
@@ -1,350 +1,350 @@
-/************************************************************************************
-
-Filename : OVR_Win32_DeviceStatus.cpp
-Content : Win32 implementation of DeviceStatus.
-Created : January 24, 2013
-Authors : Lee Cooper
-
-Copyright : Copyright 2013 Oculus VR, Inc. All Rights reserved.
-
-Use of this software is subject to the terms of the Oculus license
-agreement provided at the time of installation or download, or which
-otherwise accompanies this software in either electronic or hard copy form.
-
-*************************************************************************************/
-
-#include "OVR_Win32_DeviceStatus.h"
-
-#include "OVR_Win32_HIDDevice.h"
-
-#include "Kernel/OVR_Log.h"
-
-#include <dbt.h>
-
-namespace OVR { namespace Win32 {
-
-static TCHAR windowClassName[] = TEXT("LibOVR_DeviceStatus_WindowClass");
-
-//-------------------------------------------------------------------------------------
-DeviceStatus::DeviceStatus(Notifier* const pClient)
- : pNotificationClient(pClient), LastTimerId(0)
-{
-}
-
-bool DeviceStatus::Initialize()
-{
-
- WNDCLASS wndClass;
- wndClass.style = CS_HREDRAW | CS_VREDRAW;
- wndClass.lpfnWndProc = WindowsMessageCallback;
- wndClass.cbClsExtra = 0;
- wndClass.cbWndExtra = 0;
- wndClass.hInstance = 0;
- wndClass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
- wndClass.hCursor = LoadCursor(NULL, IDC_ARROW);
- wndClass.hbrBackground = (HBRUSH) (COLOR_WINDOW + 1);
- wndClass.lpszMenuName = NULL;
- wndClass.lpszClassName = windowClassName;
-
- if (!RegisterClass(&wndClass))
- {
- OVR_ASSERT_LOG(false, ("Failed to register window class."));
- return false;
- }
-
- // We're going to create a 'message-only' window. This will be hidden, can't be enumerated etc.
- // To do this we supply 'HWND_MESSAGE' as the hWndParent.
- // http://msdn.microsoft.com/en-us/library/ms632599%28VS.85%29.aspx#message_only
- hMessageWindow = CreateWindow( windowClassName,
- windowClassName,
- WS_OVERLAPPEDWINDOW,
- CW_USEDEFAULT,
- CW_USEDEFAULT,
- CW_USEDEFAULT,
- CW_USEDEFAULT,
- HWND_MESSAGE,
- NULL,
- 0,
- this); // Pass this object via the CREATESTRUCT mechanism
- // so that we can attach it to the window user data.
-
- if (hMessageWindow == NULL)
- {
- OVR_ASSERT_LOG(false, ("Failed to create window."));
- return false;
- }
-
- // According to MS, topmost windows receive WM_DEVICECHANGE faster.
- ::SetWindowPos(hMessageWindow, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE);
- UpdateWindow(hMessageWindow);
-
-
- // Register notification for additional HID messages.
- HIDDeviceManager* hidDeviceManager = new HIDDeviceManager(NULL);
- HidGuid = hidDeviceManager->GetHIDGuid();
- hidDeviceManager->Release();
-
- DEV_BROADCAST_DEVICEINTERFACE notificationFilter;
-
- ZeroMemory(&notificationFilter, sizeof(notificationFilter));
- notificationFilter.dbcc_size = sizeof(DEV_BROADCAST_DEVICEINTERFACE);
- notificationFilter.dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE;
- //notificationFilter.dbcc_classguid = hidguid;
-
- // We need DEVICE_NOTIFY_ALL_INTERFACE_CLASSES to detect
- // HDMI plug/unplug events.
- hDeviceNotify = RegisterDeviceNotification(
- hMessageWindow,
- &notificationFilter,
- DEVICE_NOTIFY_ALL_INTERFACE_CLASSES|DEVICE_NOTIFY_WINDOW_HANDLE);
-
- if (hDeviceNotify == NULL)
- {
- OVR_ASSERT_LOG(false, ("Failed to register for device notifications."));
- return false;
- }
-
- return true;
-}
-
-void DeviceStatus::ShutDown()
-{
- OVR_ASSERT(hMessageWindow);
-
- if (!UnregisterDeviceNotification(hDeviceNotify))
- {
- OVR_ASSERT_LOG(false, ("Failed to unregister device notification."));
- }
-
- PostMessage(hMessageWindow, WM_CLOSE, 0, 0);
-
- while (hMessageWindow != NULL)
- {
- ProcessMessages();
- Sleep(1);
- }
-
- if (!UnregisterClass(windowClassName, NULL))
- {
- OVR_ASSERT_LOG(false, ("Failed to unregister window class."));
- }
-}
-
-DeviceStatus::~DeviceStatus()
-{
- OVR_ASSERT_LOG(hMessageWindow == NULL, ("Need to call 'ShutDown' from DeviceManagerThread."));
-}
-
-void DeviceStatus::ProcessMessages()
-{
- OVR_ASSERT_LOG(hMessageWindow != NULL, ("Need to call 'Initialize' before first use."));
-
- MSG msg;
-
- // Note WM_DEVICECHANGED messages are dispatched but not retrieved by PeekMessage.
- // I think this is because they are pending, non-queued messages.
- while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
- {
- TranslateMessage(&msg);
- DispatchMessage(&msg);
- }
-}
-
-bool DeviceStatus::MessageCallback(WORD messageType, const String& devicePath)
-{
- bool rv = true;
- if (messageType == DBT_DEVICEARRIVAL)
- {
- rv = pNotificationClient->OnMessage(Notifier::DeviceAdded, devicePath);
- }
- else if (messageType == DBT_DEVICEREMOVECOMPLETE)
- {
- pNotificationClient->OnMessage(Notifier::DeviceRemoved, devicePath);
- }
- else
- {
- OVR_ASSERT(0);
- }
- return rv;
-}
-
-void DeviceStatus::CleanupRecoveryTimer(UPInt index)
-{
- ::KillTimer(hMessageWindow, RecoveryTimers[index].TimerId);
- RecoveryTimers.RemoveAt(index);
-}
-
-DeviceStatus::RecoveryTimerDesc*
-DeviceStatus::FindRecoveryTimer(UINT_PTR timerId, UPInt* pindex)
-{
- for (UPInt i = 0, n = RecoveryTimers.GetSize(); i < n; ++i)
- {
- RecoveryTimerDesc* pdesc = &RecoveryTimers[i];
- if (pdesc->TimerId == timerId)
- {
- *pindex = i;
- return pdesc;
- }
- }
- return NULL;
-}
-
-void DeviceStatus::FindAndCleanupRecoveryTimer(const String& devicePath)
-{
- for (UPInt i = 0, n = RecoveryTimers.GetSize(); i < n; ++i)
- {
- RecoveryTimerDesc* pdesc = &RecoveryTimers[i];
- if (pdesc->DevicePath.CompareNoCase(devicePath))
- {
- CleanupRecoveryTimer(i);
- break;
- }
- }
-}
-
-LRESULT CALLBACK DeviceStatus::WindowsMessageCallback( HWND hwnd,
- UINT message,
- WPARAM wParam,
- LPARAM lParam)
-{
- switch (message)
- {
- case WM_CREATE:
- {
- // Setup window user data with device status object pointer.
- LPCREATESTRUCT create_struct = reinterpret_cast<LPCREATESTRUCT>(lParam);
- void *lpCreateParam = create_struct->lpCreateParams;
- DeviceStatus *pDeviceStatus = reinterpret_cast<DeviceStatus*>(lpCreateParam);
-
- SetWindowLongPtr(hwnd, GWLP_USERDATA, reinterpret_cast<LONG_PTR>(pDeviceStatus));
- }
- return 0; // Return 0 for successfully handled WM_CREATE.
-
- case WM_DEVICECHANGE:
- {
- WORD loword = LOWORD(wParam);
-
- if (loword != DBT_DEVICEARRIVAL &&
- loword != DBT_DEVICEREMOVECOMPLETE)
- {
- // Ignore messages other than device arrive and remove complete
- // (we're not handling intermediate ones).
- return TRUE; // Grant WM_DEVICECHANGE request.
- }
-
- DEV_BROADCAST_DEVICEINTERFACE* hdr;
- hdr = (DEV_BROADCAST_DEVICEINTERFACE*) lParam;
-
- if (hdr->dbcc_devicetype != DBT_DEVTYP_DEVICEINTERFACE)
- {
- // Ignore non interface device messages.
- return TRUE; // Grant WM_DEVICECHANGE request.
- }
-
- LONG_PTR userData = GetWindowLongPtr(hwnd, GWLP_USERDATA);
- OVR_ASSERT(userData != NULL);
-
- // Call callback on device messages object with the device path.
- DeviceStatus* pDeviceStatus = (DeviceStatus*) userData;
- String devicePath(hdr->dbcc_name);
-
- // check if HID device caused the event...
- if (pDeviceStatus->HidGuid == hdr->dbcc_classguid)
- {
- // check if recovery timer is already running; stop it and
- // remove it, if so.
- pDeviceStatus->FindAndCleanupRecoveryTimer(devicePath);
-
- if (!pDeviceStatus->MessageCallback(loword, devicePath))
- {
- // hmmm.... unsuccessful
- if (loword == DBT_DEVICEARRIVAL)
- {
- // Windows sometimes may return errors ERROR_SHARING_VIOLATION and
- // ERROR_FILE_NOT_FOUND when trying to open an USB device via
- // CreateFile. Need to start a recovery timer that will try to
- // re-open the device again.
- OVR_DEBUG_LOG(("Adding failed, recovering through a timer..."));
- UINT_PTR tid = ::SetTimer(hwnd, ++pDeviceStatus->LastTimerId,
- USBRecoveryTimeInterval, NULL);
- RecoveryTimerDesc rtDesc;
- rtDesc.TimerId = tid;
- rtDesc.DevicePath = devicePath;
- rtDesc.NumAttempts= 0;
- pDeviceStatus->RecoveryTimers.PushBack(rtDesc);
- // wrap around the timer counter, avoid timerId == 0...
- if (pDeviceStatus->LastTimerId + 1 == 0)
- pDeviceStatus->LastTimerId = 0;
- }
- }
- }
- // Check if Oculus HDMI device was plugged/unplugged, preliminary
- // filtering. (is there any way to get GUID? !AB)
- //else if (strstr(devicePath.ToCStr(), "DISPLAY#"))
- else if (strstr(devicePath.ToCStr(), "#OVR00"))
- {
- pDeviceStatus->MessageCallback(loword, devicePath);
- }
- }
- return TRUE; // Grant WM_DEVICECHANGE request.
-
- case WM_TIMER:
- {
- if (wParam != 0)
- {
- LONG_PTR userData = GetWindowLongPtr(hwnd, GWLP_USERDATA);
- OVR_ASSERT(userData != NULL);
-
- // Call callback on device messages object with the device path.
- DeviceStatus* pDeviceStatus = (DeviceStatus*) userData;
-
- // Check if we have recovery timer running (actually, we must be!)
- UPInt rtIndex;
- RecoveryTimerDesc* prtDesc = pDeviceStatus->FindRecoveryTimer(wParam, &rtIndex);
- if (prtDesc)
- {
- if (pDeviceStatus->MessageCallback(DBT_DEVICEARRIVAL, prtDesc->DevicePath))
- {
- OVR_DEBUG_LOG(("Recovered, adding is successful, cleaning up the timer..."));
- // now it is successful, kill the timer and cleanup
- pDeviceStatus->CleanupRecoveryTimer(rtIndex);
- }
- else
- {
- if (++prtDesc->NumAttempts >= MaxUSBRecoveryAttempts)
- {
- OVR_DEBUG_LOG(("Failed to recover USB after %d attempts, path = '%s', aborting...",
- prtDesc->NumAttempts, prtDesc->DevicePath.ToCStr()));
- pDeviceStatus->CleanupRecoveryTimer(rtIndex);
- }
- else
- {
- OVR_DEBUG_LOG(("Failed to recover USB, %d attempts, path = '%s'",
- prtDesc->NumAttempts, prtDesc->DevicePath.ToCStr()));
- }
- }
- }
- }
- }
- return 0;
-
- case WM_CLOSE:
- {
- LONG_PTR userData = GetWindowLongPtr(hwnd, GWLP_USERDATA);
- OVR_ASSERT(userData != NULL);
- DeviceStatus* pDeviceStatus = (DeviceStatus*) userData;
- pDeviceStatus->hMessageWindow = NULL;
-
- DestroyWindow(hwnd);
- }
- return 0; // We processed the WM_CLOSE message.
-
- case WM_DESTROY:
- PostQuitMessage(0);
- return 0; // We processed the WM_DESTROY message.
- }
-
- return DefWindowProc(hwnd, message, wParam, lParam);
-}
-
-}} // namespace OVR::Win32
+/************************************************************************************
+
+Filename : OVR_Win32_DeviceStatus.cpp
+Content : Win32 implementation of DeviceStatus.
+Created : January 24, 2013
+Authors : Lee Cooper
+
+Copyright : Copyright 2013 Oculus VR, Inc. All Rights reserved.
+
+Use of this software is subject to the terms of the Oculus license
+agreement provided at the time of installation or download, or which
+otherwise accompanies this software in either electronic or hard copy form.
+
+*************************************************************************************/
+
+#include "OVR_Win32_DeviceStatus.h"
+
+#include "OVR_Win32_HIDDevice.h"
+
+#include "Kernel/OVR_Log.h"
+
+#include <dbt.h>
+
+namespace OVR { namespace Win32 {
+
+static TCHAR windowClassName[] = TEXT("LibOVR_DeviceStatus_WindowClass");
+
+//-------------------------------------------------------------------------------------
+DeviceStatus::DeviceStatus(Notifier* const pClient)
+ : pNotificationClient(pClient), LastTimerId(0)
+{
+}
+
+bool DeviceStatus::Initialize()
+{
+
+ WNDCLASS wndClass;
+ wndClass.style = CS_HREDRAW | CS_VREDRAW;
+ wndClass.lpfnWndProc = WindowsMessageCallback;
+ wndClass.cbClsExtra = 0;
+ wndClass.cbWndExtra = 0;
+ wndClass.hInstance = 0;
+ wndClass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
+ wndClass.hCursor = LoadCursor(NULL, IDC_ARROW);
+ wndClass.hbrBackground = (HBRUSH) (COLOR_WINDOW + 1);
+ wndClass.lpszMenuName = NULL;
+ wndClass.lpszClassName = windowClassName;
+
+ if (!RegisterClass(&wndClass))
+ {
+ OVR_ASSERT_LOG(false, ("Failed to register window class."));
+ return false;
+ }
+
+ // We're going to create a 'message-only' window. This will be hidden, can't be enumerated etc.
+ // To do this we supply 'HWND_MESSAGE' as the hWndParent.
+ // http://msdn.microsoft.com/en-us/library/ms632599%28VS.85%29.aspx#message_only
+ hMessageWindow = CreateWindow( windowClassName,
+ windowClassName,
+ WS_OVERLAPPEDWINDOW,
+ CW_USEDEFAULT,
+ CW_USEDEFAULT,
+ CW_USEDEFAULT,
+ CW_USEDEFAULT,
+ HWND_MESSAGE,
+ NULL,
+ 0,
+ this); // Pass this object via the CREATESTRUCT mechanism
+ // so that we can attach it to the window user data.
+
+ if (hMessageWindow == NULL)
+ {
+ OVR_ASSERT_LOG(false, ("Failed to create window."));
+ return false;
+ }
+
+ // According to MS, topmost windows receive WM_DEVICECHANGE faster.
+ ::SetWindowPos(hMessageWindow, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE);
+ UpdateWindow(hMessageWindow);
+
+
+ // Register notification for additional HID messages.
+ HIDDeviceManager* hidDeviceManager = new HIDDeviceManager(NULL);
+ HidGuid = hidDeviceManager->GetHIDGuid();
+ hidDeviceManager->Release();
+
+ DEV_BROADCAST_DEVICEINTERFACE notificationFilter;
+
+ ZeroMemory(&notificationFilter, sizeof(notificationFilter));
+ notificationFilter.dbcc_size = sizeof(DEV_BROADCAST_DEVICEINTERFACE);
+ notificationFilter.dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE;
+ //notificationFilter.dbcc_classguid = hidguid;
+
+ // We need DEVICE_NOTIFY_ALL_INTERFACE_CLASSES to detect
+ // HDMI plug/unplug events.
+ hDeviceNotify = RegisterDeviceNotification(
+ hMessageWindow,
+ &notificationFilter,
+ DEVICE_NOTIFY_ALL_INTERFACE_CLASSES|DEVICE_NOTIFY_WINDOW_HANDLE);
+
+ if (hDeviceNotify == NULL)
+ {
+ OVR_ASSERT_LOG(false, ("Failed to register for device notifications."));
+ return false;
+ }
+
+ return true;
+}
+
+void DeviceStatus::ShutDown()
+{
+ OVR_ASSERT(hMessageWindow);
+
+ if (!UnregisterDeviceNotification(hDeviceNotify))
+ {
+ OVR_ASSERT_LOG(false, ("Failed to unregister device notification."));
+ }
+
+ PostMessage(hMessageWindow, WM_CLOSE, 0, 0);
+
+ while (hMessageWindow != NULL)
+ {
+ ProcessMessages();
+ Sleep(1);
+ }
+
+ if (!UnregisterClass(windowClassName, NULL))
+ {
+ OVR_ASSERT_LOG(false, ("Failed to unregister window class."));
+ }
+}
+
+DeviceStatus::~DeviceStatus()
+{
+ OVR_ASSERT_LOG(hMessageWindow == NULL, ("Need to call 'ShutDown' from DeviceManagerThread."));
+}
+
+void DeviceStatus::ProcessMessages()
+{
+ OVR_ASSERT_LOG(hMessageWindow != NULL, ("Need to call 'Initialize' before first use."));
+
+ MSG msg;
+
+ // Note WM_DEVICECHANGED messages are dispatched but not retrieved by PeekMessage.
+ // I think this is because they are pending, non-queued messages.
+ while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
+ {
+ TranslateMessage(&msg);
+ DispatchMessage(&msg);
+ }
+}
+
+bool DeviceStatus::MessageCallback(WORD messageType, const String& devicePath)
+{
+ bool rv = true;
+ if (messageType == DBT_DEVICEARRIVAL)
+ {
+ rv = pNotificationClient->OnMessage(Notifier::DeviceAdded, devicePath);
+ }
+ else if (messageType == DBT_DEVICEREMOVECOMPLETE)
+ {
+ pNotificationClient->OnMessage(Notifier::DeviceRemoved, devicePath);
+ }
+ else
+ {
+ OVR_ASSERT(0);
+ }
+ return rv;
+}
+
+void DeviceStatus::CleanupRecoveryTimer(UPInt index)
+{
+ ::KillTimer(hMessageWindow, RecoveryTimers[index].TimerId);
+ RecoveryTimers.RemoveAt(index);
+}
+
+DeviceStatus::RecoveryTimerDesc*
+DeviceStatus::FindRecoveryTimer(UINT_PTR timerId, UPInt* pindex)
+{
+ for (UPInt i = 0, n = RecoveryTimers.GetSize(); i < n; ++i)
+ {
+ RecoveryTimerDesc* pdesc = &RecoveryTimers[i];
+ if (pdesc->TimerId == timerId)
+ {
+ *pindex = i;
+ return pdesc;
+ }
+ }
+ return NULL;
+}
+
+void DeviceStatus::FindAndCleanupRecoveryTimer(const String& devicePath)
+{
+ for (UPInt i = 0, n = RecoveryTimers.GetSize(); i < n; ++i)
+ {
+ RecoveryTimerDesc* pdesc = &RecoveryTimers[i];
+ if (pdesc->DevicePath.CompareNoCase(devicePath))
+ {
+ CleanupRecoveryTimer(i);
+ break;
+ }
+ }
+}
+
+LRESULT CALLBACK DeviceStatus::WindowsMessageCallback( HWND hwnd,
+ UINT message,
+ WPARAM wParam,
+ LPARAM lParam)
+{
+ switch (message)
+ {
+ case WM_CREATE:
+ {
+ // Setup window user data with device status object pointer.
+ LPCREATESTRUCT create_struct = reinterpret_cast<LPCREATESTRUCT>(lParam);
+ void *lpCreateParam = create_struct->lpCreateParams;
+ DeviceStatus *pDeviceStatus = reinterpret_cast<DeviceStatus*>(lpCreateParam);
+
+ SetWindowLongPtr(hwnd, GWLP_USERDATA, reinterpret_cast<LONG_PTR>(pDeviceStatus));
+ }
+ return 0; // Return 0 for successfully handled WM_CREATE.
+
+ case WM_DEVICECHANGE:
+ {
+ WORD loword = LOWORD(wParam);
+
+ if (loword != DBT_DEVICEARRIVAL &&
+ loword != DBT_DEVICEREMOVECOMPLETE)
+ {
+ // Ignore messages other than device arrive and remove complete
+ // (we're not handling intermediate ones).
+ return TRUE; // Grant WM_DEVICECHANGE request.
+ }
+
+ DEV_BROADCAST_DEVICEINTERFACE* hdr;
+ hdr = (DEV_BROADCAST_DEVICEINTERFACE*) lParam;
+
+ if (hdr->dbcc_devicetype != DBT_DEVTYP_DEVICEINTERFACE)
+ {
+ // Ignore non interface device messages.
+ return TRUE; // Grant WM_DEVICECHANGE request.
+ }
+
+ LONG_PTR userData = GetWindowLongPtr(hwnd, GWLP_USERDATA);
+ OVR_ASSERT(userData != NULL);
+
+ // Call callback on device messages object with the device path.
+ DeviceStatus* pDeviceStatus = (DeviceStatus*) userData;
+ String devicePath(hdr->dbcc_name);
+
+ // check if HID device caused the event...
+ if (pDeviceStatus->HidGuid == hdr->dbcc_classguid)
+ {
+ // check if recovery timer is already running; stop it and
+ // remove it, if so.
+ pDeviceStatus->FindAndCleanupRecoveryTimer(devicePath);
+
+ if (!pDeviceStatus->MessageCallback(loword, devicePath))
+ {
+ // hmmm.... unsuccessful
+ if (loword == DBT_DEVICEARRIVAL)
+ {
+ // Windows sometimes may return errors ERROR_SHARING_VIOLATION and
+ // ERROR_FILE_NOT_FOUND when trying to open an USB device via
+ // CreateFile. Need to start a recovery timer that will try to
+ // re-open the device again.
+ OVR_DEBUG_LOG(("Adding failed, recovering through a timer..."));
+ UINT_PTR tid = ::SetTimer(hwnd, ++pDeviceStatus->LastTimerId,
+ USBRecoveryTimeInterval, NULL);
+ RecoveryTimerDesc rtDesc;
+ rtDesc.TimerId = tid;
+ rtDesc.DevicePath = devicePath;
+ rtDesc.NumAttempts= 0;
+ pDeviceStatus->RecoveryTimers.PushBack(rtDesc);
+ // wrap around the timer counter, avoid timerId == 0...
+ if (pDeviceStatus->LastTimerId + 1 == 0)
+ pDeviceStatus->LastTimerId = 0;
+ }
+ }
+ }
+ // Check if Oculus HDMI device was plugged/unplugged, preliminary
+ // filtering. (is there any way to get GUID? !AB)
+ //else if (strstr(devicePath.ToCStr(), "DISPLAY#"))
+ else if (strstr(devicePath.ToCStr(), "#OVR00"))
+ {
+ pDeviceStatus->MessageCallback(loword, devicePath);
+ }
+ }
+ return TRUE; // Grant WM_DEVICECHANGE request.
+
+ case WM_TIMER:
+ {
+ if (wParam != 0)
+ {
+ LONG_PTR userData = GetWindowLongPtr(hwnd, GWLP_USERDATA);
+ OVR_ASSERT(userData != NULL);
+
+ // Call callback on device messages object with the device path.
+ DeviceStatus* pDeviceStatus = (DeviceStatus*) userData;
+
+ // Check if we have recovery timer running (actually, we must be!)
+ UPInt rtIndex;
+ RecoveryTimerDesc* prtDesc = pDeviceStatus->FindRecoveryTimer(wParam, &rtIndex);
+ if (prtDesc)
+ {
+ if (pDeviceStatus->MessageCallback(DBT_DEVICEARRIVAL, prtDesc->DevicePath))
+ {
+ OVR_DEBUG_LOG(("Recovered, adding is successful, cleaning up the timer..."));
+ // now it is successful, kill the timer and cleanup
+ pDeviceStatus->CleanupRecoveryTimer(rtIndex);
+ }
+ else
+ {
+ if (++prtDesc->NumAttempts >= MaxUSBRecoveryAttempts)
+ {
+ OVR_DEBUG_LOG(("Failed to recover USB after %d attempts, path = '%s', aborting...",
+ prtDesc->NumAttempts, prtDesc->DevicePath.ToCStr()));
+ pDeviceStatus->CleanupRecoveryTimer(rtIndex);
+ }
+ else
+ {
+ OVR_DEBUG_LOG(("Failed to recover USB, %d attempts, path = '%s'",
+ prtDesc->NumAttempts, prtDesc->DevicePath.ToCStr()));
+ }
+ }
+ }
+ }
+ }
+ return 0;
+
+ case WM_CLOSE:
+ {
+ LONG_PTR userData = GetWindowLongPtr(hwnd, GWLP_USERDATA);
+ OVR_ASSERT(userData != NULL);
+ DeviceStatus* pDeviceStatus = (DeviceStatus*) userData;
+ pDeviceStatus->hMessageWindow = NULL;
+
+ DestroyWindow(hwnd);
+ }
+ return 0; // We processed the WM_CLOSE message.
+
+ case WM_DESTROY:
+ PostQuitMessage(0);
+ return 0; // We processed the WM_DESTROY message.
+ }
+
+ return DefWindowProc(hwnd, message, wParam, lParam);
+}
+
+}} // namespace OVR::Win32
diff --git a/LibOVR/Src/OVR_Win32_DeviceStatus.h b/LibOVR/Src/OVR_Win32_DeviceStatus.h
index 820e3a5..669a12e 100644
--- a/LibOVR/Src/OVR_Win32_DeviceStatus.h
+++ b/LibOVR/Src/OVR_Win32_DeviceStatus.h
@@ -1,101 +1,101 @@
-/************************************************************************************
-
-Filename : OVR_Win32_DeviceStatus.h
-Content : Win32-specific DeviceStatus header.
-Created : January 24, 2013
-Authors : Lee Cooper
-
-Copyright : Copyright 2013 Oculus VR, Inc. All Rights reserved.
-
-Use of this software is subject to the terms of the Oculus license
-agreement provided at the time of installation or download, or which
-otherwise accompanies this software in either electronic or hard copy form.
-
-*************************************************************************************/
-
-#ifndef OVR_Win32_DeviceStatus_h
-#define OVR_Win32_DeviceStatus_h
-
-#include <windows.h>
-#include "Kernel/OVR_String.h"
-#include "Kernel/OVR_RefCount.h"
-#include "Kernel/OVR_Array.h"
-
-namespace OVR { namespace Win32 {
-
-//-------------------------------------------------------------------------------------
-// ***** DeviceStatus
-//
-// DeviceStatus abstracts the handling of windows messages of interest for
-// example the WM_DEVICECHANGED message which occurs when a device is plugged/unplugged.
-// The device manager thread creates an instance of this class and passes its pointer
-// in the constructor. That thread is also responsible for periodically calling 'ProcessMessages'
-// to process queued windows messages. The client is notified via the 'OnMessage' method
-// declared in the 'DeviceMessages::Notifier' interface.
-class DeviceStatus : public RefCountBase<DeviceStatus>
-{
-public:
-
- // Notifier used for device messages.
- class Notifier
- {
- public:
- enum MessageType
- {
- DeviceAdded = 0,
- DeviceRemoved = 1,
- };
-
- virtual bool OnMessage(MessageType type, const String& devicePath)
- { OVR_UNUSED2(type, devicePath); return true; }
- };
-
- DeviceStatus(Notifier* const pClient);
- ~DeviceStatus();
-
- void operator = (const DeviceStatus&); // No assignment implementation.
-
- bool Initialize();
- void ShutDown();
-
- void ProcessMessages();
-
-private:
- enum
- {
- MaxUSBRecoveryAttempts = 20,
- USBRecoveryTimeInterval = 500 // ms
- };
- struct RecoveryTimerDesc
- {
- UINT_PTR TimerId;
- String DevicePath;
- unsigned NumAttempts;
- };
-
- static LRESULT CALLBACK WindowsMessageCallback( HWND hwnd,
- UINT message,
- WPARAM wParam,
- LPARAM lParam);
-
- bool MessageCallback(WORD messageType, const String& devicePath);
-
- void CleanupRecoveryTimer(UPInt index);
- RecoveryTimerDesc* FindRecoveryTimer(UINT_PTR timerId, UPInt* pindex);
- void FindAndCleanupRecoveryTimer(const String& devicePath);
-
-private: // data
- Notifier* const pNotificationClient; // Don't reference count a back-pointer.
-
- HWND hMessageWindow;
- HDEVNOTIFY hDeviceNotify;
-
- UINT_PTR LastTimerId;
- Array<RecoveryTimerDesc> RecoveryTimers;
-
- GUID HidGuid;
-};
-
-}} // namespace OVR::Win32
-
-#endif // OVR_Win32_DeviceStatus_h
+/************************************************************************************
+
+Filename : OVR_Win32_DeviceStatus.h
+Content : Win32-specific DeviceStatus header.
+Created : January 24, 2013
+Authors : Lee Cooper
+
+Copyright : Copyright 2013 Oculus VR, Inc. All Rights reserved.
+
+Use of this software is subject to the terms of the Oculus license
+agreement provided at the time of installation or download, or which
+otherwise accompanies this software in either electronic or hard copy form.
+
+*************************************************************************************/
+
+#ifndef OVR_Win32_DeviceStatus_h
+#define OVR_Win32_DeviceStatus_h
+
+#include <windows.h>
+#include "Kernel/OVR_String.h"
+#include "Kernel/OVR_RefCount.h"
+#include "Kernel/OVR_Array.h"
+
+namespace OVR { namespace Win32 {
+
+//-------------------------------------------------------------------------------------
+// ***** DeviceStatus
+//
+// DeviceStatus abstracts the handling of windows messages of interest for
+// example the WM_DEVICECHANGED message which occurs when a device is plugged/unplugged.
+// The device manager thread creates an instance of this class and passes its pointer
+// in the constructor. That thread is also responsible for periodically calling 'ProcessMessages'
+// to process queued windows messages. The client is notified via the 'OnMessage' method
+// declared in the 'DeviceMessages::Notifier' interface.
+class DeviceStatus : public RefCountBase<DeviceStatus>
+{
+public:
+
+ // Notifier used for device messages.
+ class Notifier
+ {
+ public:
+ enum MessageType
+ {
+ DeviceAdded = 0,
+ DeviceRemoved = 1,
+ };
+
+ virtual bool OnMessage(MessageType type, const String& devicePath)
+ { OVR_UNUSED2(type, devicePath); return true; }
+ };
+
+ DeviceStatus(Notifier* const pClient);
+ ~DeviceStatus();
+
+ void operator = (const DeviceStatus&); // No assignment implementation.
+
+ bool Initialize();
+ void ShutDown();
+
+ void ProcessMessages();
+
+private:
+ enum
+ {
+ MaxUSBRecoveryAttempts = 20,
+ USBRecoveryTimeInterval = 500 // ms
+ };
+ struct RecoveryTimerDesc
+ {
+ UINT_PTR TimerId;
+ String DevicePath;
+ unsigned NumAttempts;
+ };
+
+ static LRESULT CALLBACK WindowsMessageCallback( HWND hwnd,
+ UINT message,
+ WPARAM wParam,
+ LPARAM lParam);
+
+ bool MessageCallback(WORD messageType, const String& devicePath);
+
+ void CleanupRecoveryTimer(UPInt index);
+ RecoveryTimerDesc* FindRecoveryTimer(UINT_PTR timerId, UPInt* pindex);
+ void FindAndCleanupRecoveryTimer(const String& devicePath);
+
+private: // data
+ Notifier* const pNotificationClient; // Don't reference count a back-pointer.
+
+ HWND hMessageWindow;
+ HDEVNOTIFY hDeviceNotify;
+
+ UINT_PTR LastTimerId;
+ Array<RecoveryTimerDesc> RecoveryTimers;
+
+ GUID HidGuid;
+};
+
+}} // namespace OVR::Win32
+
+#endif // OVR_Win32_DeviceStatus_h
diff --git a/LibOVR/Src/OVR_Win32_HIDDevice.cpp b/LibOVR/Src/OVR_Win32_HIDDevice.cpp
index 8c04bcf..28a47f0 100644
--- a/LibOVR/Src/OVR_Win32_HIDDevice.cpp
+++ b/LibOVR/Src/OVR_Win32_HIDDevice.cpp
@@ -1,637 +1,637 @@
-/************************************************************************************
-
-Filename : OVR_Win32_HIDDevice.cpp
-Content : Win32 HID device implementation.
-Created : February 22, 2013
-Authors : Lee Cooper
-
-Copyright : Copyright 2013 Oculus VR, Inc. All Rights reserved.
-
-Use of this software is subject to the terms of the Oculus license
-agreement provided at the time of installation or download, or which
-otherwise accompanies this software in either electronic or hard copy form.
-
-*************************************************************************************/
-
-#include "OVR_Win32_HIDDevice.h"
-#include "OVR_Win32_DeviceManager.h"
-
-#include "Kernel/OVR_System.h"
-#include "Kernel/OVR_Log.h"
-
-namespace OVR { namespace Win32 {
-
-//-------------------------------------------------------------------------------------
-// HIDDevicePathWrapper is a simple class used to extract HID device file path
-// through SetupDiGetDeviceInterfaceDetail. We use a class since this is a bit messy.
-class HIDDevicePathWrapper
-{
- SP_INTERFACE_DEVICE_DETAIL_DATA_A* pData;
-public:
- HIDDevicePathWrapper() : pData(0) { }
- ~HIDDevicePathWrapper() { if (pData) OVR_FREE(pData); }
-
- const char* GetPath() const { return pData ? pData->DevicePath : 0; }
-
- bool InitPathFromInterfaceData(HDEVINFO hdevInfoSet, SP_DEVICE_INTERFACE_DATA* pidata);
-};
-
-bool HIDDevicePathWrapper::InitPathFromInterfaceData(HDEVINFO hdevInfoSet, SP_DEVICE_INTERFACE_DATA* pidata)
-{
- DWORD detailSize = 0;
- // SetupDiGetDeviceInterfaceDetailA returns "not enough buffer error code"
- // doe size request. Just check valid size.
- SetupDiGetDeviceInterfaceDetailA(hdevInfoSet, pidata, NULL, 0, &detailSize, NULL);
- if (!detailSize ||
- ((pData = (SP_INTERFACE_DEVICE_DETAIL_DATA_A*)OVR_ALLOC(detailSize)) == 0))
- return false;
- pData->cbSize = sizeof(SP_INTERFACE_DEVICE_DETAIL_DATA_A);
-
- if (!SetupDiGetDeviceInterfaceDetailA(hdevInfoSet, pidata, pData, detailSize, NULL, NULL))
- return false;
- return true;
-}
-
-
-//-------------------------------------------------------------------------------------
-// **** Win32::DeviceManager
-
-HIDDeviceManager::HIDDeviceManager(DeviceManager* manager)
- : Manager(manager)
-{
- hHidLib = ::LoadLibraryA("hid.dll");
- OVR_ASSERT_LOG(hHidLib, ("Couldn't load Win32 'hid.dll'."));
-
- OVR_RESOLVE_HIDFUNC(HidD_GetHidGuid);
- OVR_RESOLVE_HIDFUNC(HidD_SetNumInputBuffers);
- OVR_RESOLVE_HIDFUNC(HidD_GetFeature);
- OVR_RESOLVE_HIDFUNC(HidD_SetFeature);
- OVR_RESOLVE_HIDFUNC(HidD_GetAttributes);
- OVR_RESOLVE_HIDFUNC(HidD_GetManufacturerString);
- OVR_RESOLVE_HIDFUNC(HidD_GetProductString);
- OVR_RESOLVE_HIDFUNC(HidD_GetSerialNumberString);
- OVR_RESOLVE_HIDFUNC(HidD_GetPreparsedData);
- OVR_RESOLVE_HIDFUNC(HidD_FreePreparsedData);
- OVR_RESOLVE_HIDFUNC(HidP_GetCaps);
-
- if (HidD_GetHidGuid)
- HidD_GetHidGuid(&HidGuid);
-}
-
-HIDDeviceManager::~HIDDeviceManager()
-{
- ::FreeLibrary(hHidLib);
-}
-
-bool HIDDeviceManager::Initialize()
-{
- return true;
-}
-
-void HIDDeviceManager::Shutdown()
-{
- LogText("OVR::Win32::HIDDeviceManager - shutting down.\n");
-}
-
-bool HIDDeviceManager::Enumerate(HIDEnumerateVisitor* enumVisitor)
-{
- HDEVINFO hdevInfoSet;
- SP_DEVICE_INTERFACE_DATA interfaceData;
- interfaceData.cbSize = sizeof(interfaceData);
-
- // Get handle to info data set describing all available HIDs.
- hdevInfoSet = SetupDiGetClassDevsA(&HidGuid, NULL, NULL, DIGCF_INTERFACEDEVICE | DIGCF_PRESENT);
- if (hdevInfoSet == INVALID_HANDLE_VALUE)
- return false;
-
- for(int deviceIndex = 0;
- SetupDiEnumDeviceInterfaces(hdevInfoSet, NULL, &HidGuid, deviceIndex, &interfaceData);
- deviceIndex++)
- {
- // For each device, we extract its file path and open it to get attributes,
- // such as vendor and product id. If anything goes wrong, we move onto next device.
- HIDDevicePathWrapper pathWrapper;
- if (!pathWrapper.InitPathFromInterfaceData(hdevInfoSet, &interfaceData))
- continue;
-
- // Look for the device to check if it is already opened.
- Ptr<DeviceCreateDesc> existingDevice = Manager->FindDevice(pathWrapper.GetPath());
- // if device exists and it is opened then most likely the CreateHIDFile
- // will fail; therefore, we just set Enumerated to 'true' and continue.
- if (existingDevice && existingDevice->pDevice)
- {
- existingDevice->Enumerated = true;
- continue;
- }
-
- // open device in non-exclusive mode for detection...
- HANDLE hidDev = CreateHIDFile(pathWrapper.GetPath(), false);
- if (hidDev == INVALID_HANDLE_VALUE)
- continue;
-
- HIDDeviceDesc devDesc;
- devDesc.Path = pathWrapper.GetPath();
- if (initVendorProductVersion(hidDev, &devDesc) &&
- enumVisitor->MatchVendorProduct(devDesc.VendorId, devDesc.ProductId) &&
- initUsage(hidDev, &devDesc))
- {
- initStrings(hidDev, &devDesc);
-
- // Construct minimal device that the visitor callback can get feature reports from.
- Win32::HIDDevice device(this, hidDev);
- enumVisitor->Visit(device, devDesc);
- }
-
- ::CloseHandle(hidDev);
- }
-
- SetupDiDestroyDeviceInfoList(hdevInfoSet);
- return true;
-}
-
-bool HIDDeviceManager::GetHIDDeviceDesc(const String& path, HIDDeviceDesc* pdevDesc) const
-{
- // open device in non-exclusive mode for detection...
- HANDLE hidDev = CreateHIDFile(path, false);
- if (hidDev == INVALID_HANDLE_VALUE)
- return false;
-
- pdevDesc->Path = path;
- getFullDesc(hidDev, pdevDesc);
-
- ::CloseHandle(hidDev);
- return true;
-}
-
-OVR::HIDDevice* HIDDeviceManager::Open(const String& path)
-{
-
- Ptr<Win32::HIDDevice> device = *new Win32::HIDDevice(this);
-
- if (device->HIDInitialize(path))
- {
- device->AddRef();
- return device;
- }
-
- return NULL;
-}
-
-bool HIDDeviceManager::getFullDesc(HANDLE hidDev, HIDDeviceDesc* desc) const
-{
-
- if (!initVendorProductVersion(hidDev, desc))
- {
- return false;
- }
-
- if (!initUsage(hidDev, desc))
- {
- return false;
- }
-
- initStrings(hidDev, desc);
-
- return true;
-}
-
-bool HIDDeviceManager::initVendorProductVersion(HANDLE hidDev, HIDDeviceDesc* desc) const
-{
- HIDD_ATTRIBUTES attr;
- attr.Size = sizeof(attr);
- if (!HidD_GetAttributes(hidDev, &attr))
- return false;
- desc->VendorId = attr.VendorID;
- desc->ProductId = attr.ProductID;
- desc->VersionNumber = attr.VersionNumber;
- return true;
-}
-
-bool HIDDeviceManager::initUsage(HANDLE hidDev, HIDDeviceDesc* desc) const
-{
- bool result = false;
- HIDP_CAPS caps;
- HIDP_PREPARSED_DATA* preparsedData = 0;
-
- if (!HidD_GetPreparsedData(hidDev, &preparsedData))
- return false;
-
- if (HidP_GetCaps(preparsedData, &caps) == HIDP_STATUS_SUCCESS)
- {
- desc->Usage = caps.Usage;
- desc->UsagePage = caps.UsagePage;
- result = true;
- }
- HidD_FreePreparsedData(preparsedData);
- return result;
-}
-
-void HIDDeviceManager::initStrings(HANDLE hidDev, HIDDeviceDesc* desc) const
-{
- // Documentation mentions 126 as being the max for USB.
- wchar_t strBuffer[196];
-
- // HidD_Get*String functions return nothing in buffer on failure,
- // so it's ok to do this without further error checking.
- strBuffer[0] = 0;
- HidD_GetManufacturerString(hidDev, strBuffer, sizeof(strBuffer));
- desc->Manufacturer = strBuffer;
-
- strBuffer[0] = 0;
- HidD_GetProductString(hidDev, strBuffer, sizeof(strBuffer));
- desc->Product = strBuffer;
-
- strBuffer[0] = 0;
- HidD_GetSerialNumberString(hidDev, strBuffer, sizeof(strBuffer));
- desc->SerialNumber = strBuffer;
-}
-
-//-------------------------------------------------------------------------------------
-// **** Win32::HIDDevice
-
-HIDDevice::HIDDevice(HIDDeviceManager* manager)
- : HIDManager(manager), inMinimalMode(false), Device(0), ReadRequested(false)
-{
- memset(&ReadOverlapped, 0, sizeof(OVERLAPPED));
-}
-
-// This is a minimal constructor used during enumeration for us to pass
-// a HIDDevice to the visit function (so that it can query feature reports).
-HIDDevice::HIDDevice(HIDDeviceManager* manager, HANDLE device)
- : HIDManager(manager), inMinimalMode(true), Device(device), ReadRequested(true)
-{
- memset(&ReadOverlapped, 0, sizeof(OVERLAPPED));
-}
-
-HIDDevice::~HIDDevice()
-{
- if (!inMinimalMode)
- {
- HIDShutdown();
- }
-}
-
-bool HIDDevice::HIDInitialize(const String& path)
-{
-
- DevDesc.Path = path;
-
- if (!openDevice())
- {
- LogText("OVR::Win32::HIDDevice - Failed to open HIDDevice: ", path);
- return false;
- }
-
-
- HIDManager->Manager->pThread->AddTicksNotifier(this);
- HIDManager->Manager->pThread->AddMessageNotifier(this);
-
- LogText("OVR::Win32::HIDDevice - Opened '%s'\n"
- " Manufacturer:'%s' Product:'%s' Serial#:'%s'\n",
- DevDesc.Path.ToCStr(),
- DevDesc.Manufacturer.ToCStr(), DevDesc.Product.ToCStr(),
- DevDesc.SerialNumber.ToCStr());
-
- return true;
-}
-
-bool HIDDevice::initInfo()
-{
- // Device must have been successfully opened.
- OVR_ASSERT(Device);
-
- // Get report lengths.
- HIDP_PREPARSED_DATA* preparsedData = 0;
- if (!HIDManager->HidD_GetPreparsedData(Device, &preparsedData))
- {
- return false;
- }
-
- HIDP_CAPS caps;
- if (HIDManager->HidP_GetCaps(preparsedData, &caps) != HIDP_STATUS_SUCCESS)
- {
- HIDManager->HidD_FreePreparsedData(preparsedData);
- return false;
- }
-
- InputReportBufferLength = caps.InputReportByteLength;
- OutputReportBufferLength = caps.OutputReportByteLength;
- FeatureReportBufferLength= caps.FeatureReportByteLength;
- HIDManager->HidD_FreePreparsedData(preparsedData);
-
- if (ReadBufferSize < InputReportBufferLength)
- {
- OVR_ASSERT_LOG(false, ("Input report buffer length is bigger than read buffer."));
- return false;
- }
-
- // Get device desc.
- if (!HIDManager->getFullDesc(Device, &DevDesc))
- {
- OVR_ASSERT_LOG(false, ("Failed to get device desc while initializing device."));
- return false;
- }
-
- return true;
-}
-
-bool HIDDevice::openDevice()
-{
- memset(&ReadOverlapped, 0, sizeof(OVERLAPPED));
-
- Device = HIDManager->CreateHIDFile(DevDesc.Path.ToCStr());
- if (Device == INVALID_HANDLE_VALUE)
- {
- OVR_DEBUG_LOG(("Failed 'CreateHIDFile' while opening device, error = 0x%X.",
- ::GetLastError()));
- Device = 0;
- return false;
- }
-
- if (!HIDManager->HidD_SetNumInputBuffers(Device, 128))
- {
- OVR_ASSERT_LOG(false, ("Failed 'HidD_SetNumInputBuffers' while initializing device."));
- ::CloseHandle(Device);
- Device = 0;
- return false;
- }
-
-
- // Create a manual-reset non-signaled event.
- ReadOverlapped.hEvent = ::CreateEvent(0, TRUE, FALSE, 0);
-
- if (!ReadOverlapped.hEvent)
- {
- OVR_ASSERT_LOG(false, ("Failed to create event."));
- ::CloseHandle(Device);
- Device = 0;
- return false;
- }
-
- if (!initInfo())
- {
- OVR_ASSERT_LOG(false, ("Failed to get HIDDevice info."));
-
- ::CloseHandle(ReadOverlapped.hEvent);
- memset(&ReadOverlapped, 0, sizeof(OVERLAPPED));
-
- ::CloseHandle(Device);
- Device = 0;
- return false;
- }
-
- if (!initializeRead())
- {
- OVR_ASSERT_LOG(false, ("Failed to get intialize read for HIDDevice."));
-
- ::CloseHandle(ReadOverlapped.hEvent);
- memset(&ReadOverlapped, 0, sizeof(OVERLAPPED));
-
- ::CloseHandle(Device);
- Device = 0;
- return false;
- }
-
- return true;
-}
-
-void HIDDevice::HIDShutdown()
-{
-
- HIDManager->Manager->pThread->RemoveTicksNotifier(this);
- HIDManager->Manager->pThread->RemoveMessageNotifier(this);
-
- closeDevice();
- LogText("OVR::Win32::HIDDevice - Closed '%s'\n", DevDesc.Path.ToCStr());
-}
-
-bool HIDDevice::initializeRead()
-{
-
- if (!ReadRequested)
- {
- HIDManager->Manager->pThread->AddOverlappedEvent(this, ReadOverlapped.hEvent);
- ReadRequested = true;
- }
-
- // Read resets the event...
- while(::ReadFile(Device, ReadBuffer, InputReportBufferLength, 0, &ReadOverlapped))
- {
- processReadResult();
- }
-
- if (GetLastError() != ERROR_IO_PENDING)
- {
- // Some other error (such as unplugged).
- closeDeviceOnIOError();
- return false;
- }
-
- return true;
-}
-
-bool HIDDevice::processReadResult()
-{
-
- OVR_ASSERT(ReadRequested);
-
- DWORD bytesRead = 0;
-
- if (GetOverlappedResult(Device, &ReadOverlapped, &bytesRead, FALSE))
- {
- // We've got data.
- if (Handler)
- {
- Handler->OnInputReport(ReadBuffer, bytesRead);
- }
-
- // TBD: Not needed?
- // Event should be reset by Read call...
- ReadOverlapped.Pointer = 0;
- ReadOverlapped.Internal = 0;
- ReadOverlapped.InternalHigh = 0;
- return true;
- }
- else
- {
- if (GetLastError() != ERROR_IO_PENDING)
- {
- closeDeviceOnIOError();
- return false;
- }
- }
-
- return false;
-}
-
-void HIDDevice::closeDevice()
-{
- if (ReadRequested)
- {
- HIDManager->Manager->pThread->RemoveOverlappedEvent(this, ReadOverlapped.hEvent);
- ReadRequested = false;
- // Must call this to avoid Win32 assertion; CloseHandle is not enough.
- ::CancelIo(Device);
- }
-
- ::CloseHandle(ReadOverlapped.hEvent);
- memset(&ReadOverlapped, 0, sizeof(OVERLAPPED));
-
- ::CloseHandle(Device);
- Device = 0;
-}
-
-void HIDDevice::closeDeviceOnIOError()
-{
- LogText("OVR::Win32::HIDDevice - Lost connection to '%s'\n", DevDesc.Path.ToCStr());
- closeDevice();
-}
-
-bool HIDDevice::SetFeatureReport(UByte* data, UInt32 length)
-{
- if (!ReadRequested)
- return false;
-
- return HIDManager->HidD_SetFeature(Device, data, (ULONG) length) != FALSE;
-}
-
-bool HIDDevice::GetFeatureReport(UByte* data, UInt32 length)
-{
- if (!ReadRequested)
- return false;
-
- return HIDManager->HidD_GetFeature(Device, data, (ULONG) length) != FALSE;
-}
-
-void HIDDevice::OnOverlappedEvent(HANDLE hevent)
-{
- OVR_UNUSED(hevent);
- OVR_ASSERT(hevent == ReadOverlapped.hEvent);
-
- if (processReadResult())
- {
- // Proceed to read again.
- initializeRead();
- }
-}
-
-UInt64 HIDDevice::OnTicks(UInt64 ticksMks)
-{
- if (Handler)
- {
- return Handler->OnTicks(ticksMks);
- }
-
- return DeviceManagerThread::Notifier::OnTicks(ticksMks);
-}
-
-bool HIDDevice::OnDeviceMessage(DeviceMessageType messageType,
- const String& devicePath,
- bool* error)
-{
-
- // Is this the correct device?
- if (DevDesc.Path.CompareNoCase(devicePath) != 0)
- {
- return false;
- }
-
- if (messageType == DeviceMessage_DeviceAdded && !Device)
- {
- // A closed device has been re-added. Try to reopen.
- if (!openDevice())
- {
- LogError("OVR::Win32::HIDDevice - Failed to reopen a device '%s' that was re-added.\n", devicePath.ToCStr());
- *error = true;
- return true;
- }
-
- LogText("OVR::Win32::HIDDevice - Reopened device '%s'\n", devicePath.ToCStr());
- }
-
- HIDHandler::HIDDeviceMessageType handlerMessageType = HIDHandler::HIDDeviceMessage_DeviceAdded;
- if (messageType == DeviceMessage_DeviceAdded)
- {
- }
- else if (messageType == DeviceMessage_DeviceRemoved)
- {
- handlerMessageType = HIDHandler::HIDDeviceMessage_DeviceRemoved;
- }
- else
- {
- OVR_ASSERT(0);
- }
-
- if (Handler)
- {
- Handler->OnDeviceMessage(handlerMessageType);
- }
-
- *error = false;
- return true;
-}
-
-HIDDeviceManager* HIDDeviceManager::CreateInternal(Win32::DeviceManager* devManager)
-{
-
- if (!System::IsInitialized())
- {
- // Use custom message, since Log is not yet installed.
- OVR_DEBUG_STATEMENT(Log::GetDefaultLog()->
- LogMessage(Log_Debug, "HIDDeviceManager::Create failed - OVR::System not initialized"); );
- return 0;
- }
-
- Ptr<Win32::HIDDeviceManager> manager = *new Win32::HIDDeviceManager(devManager);
-
- if (manager)
- {
- if (manager->Initialize())
- {
- manager->AddRef();
- }
- else
- {
- manager.Clear();
- }
- }
-
- return manager.GetPtr();
-}
-
-} // namespace Win32
-
-//-------------------------------------------------------------------------------------
-// ***** Creation
-
-// Creates a new HIDDeviceManager and initializes OVR.
-HIDDeviceManager* HIDDeviceManager::Create()
-{
- OVR_ASSERT_LOG(false, ("Standalone mode not implemented yet."));
-
- if (!System::IsInitialized())
- {
- // Use custom message, since Log is not yet installed.
- OVR_DEBUG_STATEMENT(Log::GetDefaultLog()->
- LogMessage(Log_Debug, "HIDDeviceManager::Create failed - OVR::System not initialized"); );
- return 0;
- }
-
- Ptr<Win32::HIDDeviceManager> manager = *new Win32::HIDDeviceManager(NULL);
-
- if (manager)
- {
- if (manager->Initialize())
- {
- manager->AddRef();
- }
- else
- {
- manager.Clear();
- }
- }
-
- return manager.GetPtr();
-}
-
-} // namespace OVR
+/************************************************************************************
+
+Filename : OVR_Win32_HIDDevice.cpp
+Content : Win32 HID device implementation.
+Created : February 22, 2013
+Authors : Lee Cooper
+
+Copyright : Copyright 2013 Oculus VR, Inc. All Rights reserved.
+
+Use of this software is subject to the terms of the Oculus license
+agreement provided at the time of installation or download, or which
+otherwise accompanies this software in either electronic or hard copy form.
+
+*************************************************************************************/
+
+#include "OVR_Win32_HIDDevice.h"
+#include "OVR_Win32_DeviceManager.h"
+
+#include "Kernel/OVR_System.h"
+#include "Kernel/OVR_Log.h"
+
+namespace OVR { namespace Win32 {
+
+//-------------------------------------------------------------------------------------
+// HIDDevicePathWrapper is a simple class used to extract HID device file path
+// through SetupDiGetDeviceInterfaceDetail. We use a class since this is a bit messy.
+class HIDDevicePathWrapper
+{
+ SP_INTERFACE_DEVICE_DETAIL_DATA_A* pData;
+public:
+ HIDDevicePathWrapper() : pData(0) { }
+ ~HIDDevicePathWrapper() { if (pData) OVR_FREE(pData); }
+
+ const char* GetPath() const { return pData ? pData->DevicePath : 0; }
+
+ bool InitPathFromInterfaceData(HDEVINFO hdevInfoSet, SP_DEVICE_INTERFACE_DATA* pidata);
+};
+
+bool HIDDevicePathWrapper::InitPathFromInterfaceData(HDEVINFO hdevInfoSet, SP_DEVICE_INTERFACE_DATA* pidata)
+{
+ DWORD detailSize = 0;
+ // SetupDiGetDeviceInterfaceDetailA returns "not enough buffer error code"
+ // doe size request. Just check valid size.
+ SetupDiGetDeviceInterfaceDetailA(hdevInfoSet, pidata, NULL, 0, &detailSize, NULL);
+ if (!detailSize ||
+ ((pData = (SP_INTERFACE_DEVICE_DETAIL_DATA_A*)OVR_ALLOC(detailSize)) == 0))
+ return false;
+ pData->cbSize = sizeof(SP_INTERFACE_DEVICE_DETAIL_DATA_A);
+
+ if (!SetupDiGetDeviceInterfaceDetailA(hdevInfoSet, pidata, pData, detailSize, NULL, NULL))
+ return false;
+ return true;
+}
+
+
+//-------------------------------------------------------------------------------------
+// **** Win32::DeviceManager
+
+HIDDeviceManager::HIDDeviceManager(DeviceManager* manager)
+ : Manager(manager)
+{
+ hHidLib = ::LoadLibraryA("hid.dll");
+ OVR_ASSERT_LOG(hHidLib, ("Couldn't load Win32 'hid.dll'."));
+
+ OVR_RESOLVE_HIDFUNC(HidD_GetHidGuid);
+ OVR_RESOLVE_HIDFUNC(HidD_SetNumInputBuffers);
+ OVR_RESOLVE_HIDFUNC(HidD_GetFeature);
+ OVR_RESOLVE_HIDFUNC(HidD_SetFeature);
+ OVR_RESOLVE_HIDFUNC(HidD_GetAttributes);
+ OVR_RESOLVE_HIDFUNC(HidD_GetManufacturerString);
+ OVR_RESOLVE_HIDFUNC(HidD_GetProductString);
+ OVR_RESOLVE_HIDFUNC(HidD_GetSerialNumberString);
+ OVR_RESOLVE_HIDFUNC(HidD_GetPreparsedData);
+ OVR_RESOLVE_HIDFUNC(HidD_FreePreparsedData);
+ OVR_RESOLVE_HIDFUNC(HidP_GetCaps);
+
+ if (HidD_GetHidGuid)
+ HidD_GetHidGuid(&HidGuid);
+}
+
+HIDDeviceManager::~HIDDeviceManager()
+{
+ ::FreeLibrary(hHidLib);
+}
+
+bool HIDDeviceManager::Initialize()
+{
+ return true;
+}
+
+void HIDDeviceManager::Shutdown()
+{
+ LogText("OVR::Win32::HIDDeviceManager - shutting down.\n");
+}
+
+bool HIDDeviceManager::Enumerate(HIDEnumerateVisitor* enumVisitor)
+{
+ HDEVINFO hdevInfoSet;
+ SP_DEVICE_INTERFACE_DATA interfaceData;
+ interfaceData.cbSize = sizeof(interfaceData);
+
+ // Get handle to info data set describing all available HIDs.
+ hdevInfoSet = SetupDiGetClassDevsA(&HidGuid, NULL, NULL, DIGCF_INTERFACEDEVICE | DIGCF_PRESENT);
+ if (hdevInfoSet == INVALID_HANDLE_VALUE)
+ return false;
+
+ for(int deviceIndex = 0;
+ SetupDiEnumDeviceInterfaces(hdevInfoSet, NULL, &HidGuid, deviceIndex, &interfaceData);
+ deviceIndex++)
+ {
+ // For each device, we extract its file path and open it to get attributes,
+ // such as vendor and product id. If anything goes wrong, we move onto next device.
+ HIDDevicePathWrapper pathWrapper;
+ if (!pathWrapper.InitPathFromInterfaceData(hdevInfoSet, &interfaceData))
+ continue;
+
+ // Look for the device to check if it is already opened.
+ Ptr<DeviceCreateDesc> existingDevice = Manager->FindDevice(pathWrapper.GetPath());
+ // if device exists and it is opened then most likely the CreateHIDFile
+ // will fail; therefore, we just set Enumerated to 'true' and continue.
+ if (existingDevice && existingDevice->pDevice)
+ {
+ existingDevice->Enumerated = true;
+ continue;
+ }
+
+ // open device in non-exclusive mode for detection...
+ HANDLE hidDev = CreateHIDFile(pathWrapper.GetPath(), false);
+ if (hidDev == INVALID_HANDLE_VALUE)
+ continue;
+
+ HIDDeviceDesc devDesc;
+ devDesc.Path = pathWrapper.GetPath();
+ if (initVendorProductVersion(hidDev, &devDesc) &&
+ enumVisitor->MatchVendorProduct(devDesc.VendorId, devDesc.ProductId) &&
+ initUsage(hidDev, &devDesc))
+ {
+ initStrings(hidDev, &devDesc);
+
+ // Construct minimal device that the visitor callback can get feature reports from.
+ Win32::HIDDevice device(this, hidDev);
+ enumVisitor->Visit(device, devDesc);
+ }
+
+ ::CloseHandle(hidDev);
+ }
+
+ SetupDiDestroyDeviceInfoList(hdevInfoSet);
+ return true;
+}
+
+bool HIDDeviceManager::GetHIDDeviceDesc(const String& path, HIDDeviceDesc* pdevDesc) const
+{
+ // open device in non-exclusive mode for detection...
+ HANDLE hidDev = CreateHIDFile(path, false);
+ if (hidDev == INVALID_HANDLE_VALUE)
+ return false;
+
+ pdevDesc->Path = path;
+ getFullDesc(hidDev, pdevDesc);
+
+ ::CloseHandle(hidDev);
+ return true;
+}
+
+OVR::HIDDevice* HIDDeviceManager::Open(const String& path)
+{
+
+ Ptr<Win32::HIDDevice> device = *new Win32::HIDDevice(this);
+
+ if (device->HIDInitialize(path))
+ {
+ device->AddRef();
+ return device;
+ }
+
+ return NULL;
+}
+
+bool HIDDeviceManager::getFullDesc(HANDLE hidDev, HIDDeviceDesc* desc) const
+{
+
+ if (!initVendorProductVersion(hidDev, desc))
+ {
+ return false;
+ }
+
+ if (!initUsage(hidDev, desc))
+ {
+ return false;
+ }
+
+ initStrings(hidDev, desc);
+
+ return true;
+}
+
+bool HIDDeviceManager::initVendorProductVersion(HANDLE hidDev, HIDDeviceDesc* desc) const
+{
+ HIDD_ATTRIBUTES attr;
+ attr.Size = sizeof(attr);
+ if (!HidD_GetAttributes(hidDev, &attr))
+ return false;
+ desc->VendorId = attr.VendorID;
+ desc->ProductId = attr.ProductID;
+ desc->VersionNumber = attr.VersionNumber;
+ return true;
+}
+
+bool HIDDeviceManager::initUsage(HANDLE hidDev, HIDDeviceDesc* desc) const
+{
+ bool result = false;
+ HIDP_CAPS caps;
+ HIDP_PREPARSED_DATA* preparsedData = 0;
+
+ if (!HidD_GetPreparsedData(hidDev, &preparsedData))
+ return false;
+
+ if (HidP_GetCaps(preparsedData, &caps) == HIDP_STATUS_SUCCESS)
+ {
+ desc->Usage = caps.Usage;
+ desc->UsagePage = caps.UsagePage;
+ result = true;
+ }
+ HidD_FreePreparsedData(preparsedData);
+ return result;
+}
+
+void HIDDeviceManager::initStrings(HANDLE hidDev, HIDDeviceDesc* desc) const
+{
+ // Documentation mentions 126 as being the max for USB.
+ wchar_t strBuffer[196];
+
+ // HidD_Get*String functions return nothing in buffer on failure,
+ // so it's ok to do this without further error checking.
+ strBuffer[0] = 0;
+ HidD_GetManufacturerString(hidDev, strBuffer, sizeof(strBuffer));
+ desc->Manufacturer = strBuffer;
+
+ strBuffer[0] = 0;
+ HidD_GetProductString(hidDev, strBuffer, sizeof(strBuffer));
+ desc->Product = strBuffer;
+
+ strBuffer[0] = 0;
+ HidD_GetSerialNumberString(hidDev, strBuffer, sizeof(strBuffer));
+ desc->SerialNumber = strBuffer;
+}
+
+//-------------------------------------------------------------------------------------
+// **** Win32::HIDDevice
+
+HIDDevice::HIDDevice(HIDDeviceManager* manager)
+ : HIDManager(manager), inMinimalMode(false), Device(0), ReadRequested(false)
+{
+ memset(&ReadOverlapped, 0, sizeof(OVERLAPPED));
+}
+
+// This is a minimal constructor used during enumeration for us to pass
+// a HIDDevice to the visit function (so that it can query feature reports).
+HIDDevice::HIDDevice(HIDDeviceManager* manager, HANDLE device)
+ : HIDManager(manager), inMinimalMode(true), Device(device), ReadRequested(true)
+{
+ memset(&ReadOverlapped, 0, sizeof(OVERLAPPED));
+}
+
+HIDDevice::~HIDDevice()
+{
+ if (!inMinimalMode)
+ {
+ HIDShutdown();
+ }
+}
+
+bool HIDDevice::HIDInitialize(const String& path)
+{
+
+ DevDesc.Path = path;
+
+ if (!openDevice())
+ {
+ LogText("OVR::Win32::HIDDevice - Failed to open HIDDevice: ", path);
+ return false;
+ }
+
+
+ HIDManager->Manager->pThread->AddTicksNotifier(this);
+ HIDManager->Manager->pThread->AddMessageNotifier(this);
+
+ LogText("OVR::Win32::HIDDevice - Opened '%s'\n"
+ " Manufacturer:'%s' Product:'%s' Serial#:'%s'\n",
+ DevDesc.Path.ToCStr(),
+ DevDesc.Manufacturer.ToCStr(), DevDesc.Product.ToCStr(),
+ DevDesc.SerialNumber.ToCStr());
+
+ return true;
+}
+
+bool HIDDevice::initInfo()
+{
+ // Device must have been successfully opened.
+ OVR_ASSERT(Device);
+
+ // Get report lengths.
+ HIDP_PREPARSED_DATA* preparsedData = 0;
+ if (!HIDManager->HidD_GetPreparsedData(Device, &preparsedData))
+ {
+ return false;
+ }
+
+ HIDP_CAPS caps;
+ if (HIDManager->HidP_GetCaps(preparsedData, &caps) != HIDP_STATUS_SUCCESS)
+ {
+ HIDManager->HidD_FreePreparsedData(preparsedData);
+ return false;
+ }
+
+ InputReportBufferLength = caps.InputReportByteLength;
+ OutputReportBufferLength = caps.OutputReportByteLength;
+ FeatureReportBufferLength= caps.FeatureReportByteLength;
+ HIDManager->HidD_FreePreparsedData(preparsedData);
+
+ if (ReadBufferSize < InputReportBufferLength)
+ {
+ OVR_ASSERT_LOG(false, ("Input report buffer length is bigger than read buffer."));
+ return false;
+ }
+
+ // Get device desc.
+ if (!HIDManager->getFullDesc(Device, &DevDesc))
+ {
+ OVR_ASSERT_LOG(false, ("Failed to get device desc while initializing device."));
+ return false;
+ }
+
+ return true;
+}
+
+bool HIDDevice::openDevice()
+{
+ memset(&ReadOverlapped, 0, sizeof(OVERLAPPED));
+
+ Device = HIDManager->CreateHIDFile(DevDesc.Path.ToCStr());
+ if (Device == INVALID_HANDLE_VALUE)
+ {
+ OVR_DEBUG_LOG(("Failed 'CreateHIDFile' while opening device, error = 0x%X.",
+ ::GetLastError()));
+ Device = 0;
+ return false;
+ }
+
+ if (!HIDManager->HidD_SetNumInputBuffers(Device, 128))
+ {
+ OVR_ASSERT_LOG(false, ("Failed 'HidD_SetNumInputBuffers' while initializing device."));
+ ::CloseHandle(Device);
+ Device = 0;
+ return false;
+ }
+
+
+ // Create a manual-reset non-signaled event.
+ ReadOverlapped.hEvent = ::CreateEvent(0, TRUE, FALSE, 0);
+
+ if (!ReadOverlapped.hEvent)
+ {
+ OVR_ASSERT_LOG(false, ("Failed to create event."));
+ ::CloseHandle(Device);
+ Device = 0;
+ return false;
+ }
+
+ if (!initInfo())
+ {
+ OVR_ASSERT_LOG(false, ("Failed to get HIDDevice info."));
+
+ ::CloseHandle(ReadOverlapped.hEvent);
+ memset(&ReadOverlapped, 0, sizeof(OVERLAPPED));
+
+ ::CloseHandle(Device);
+ Device = 0;
+ return false;
+ }
+
+ if (!initializeRead())
+ {
+ OVR_ASSERT_LOG(false, ("Failed to get intialize read for HIDDevice."));
+
+ ::CloseHandle(ReadOverlapped.hEvent);
+ memset(&ReadOverlapped, 0, sizeof(OVERLAPPED));
+
+ ::CloseHandle(Device);
+ Device = 0;
+ return false;
+ }
+
+ return true;
+}
+
+void HIDDevice::HIDShutdown()
+{
+
+ HIDManager->Manager->pThread->RemoveTicksNotifier(this);
+ HIDManager->Manager->pThread->RemoveMessageNotifier(this);
+
+ closeDevice();
+ LogText("OVR::Win32::HIDDevice - Closed '%s'\n", DevDesc.Path.ToCStr());
+}
+
+bool HIDDevice::initializeRead()
+{
+
+ if (!ReadRequested)
+ {
+ HIDManager->Manager->pThread->AddOverlappedEvent(this, ReadOverlapped.hEvent);
+ ReadRequested = true;
+ }
+
+ // Read resets the event...
+ while(::ReadFile(Device, ReadBuffer, InputReportBufferLength, 0, &ReadOverlapped))
+ {
+ processReadResult();
+ }
+
+ if (GetLastError() != ERROR_IO_PENDING)
+ {
+ // Some other error (such as unplugged).
+ closeDeviceOnIOError();
+ return false;
+ }
+
+ return true;
+}
+
+bool HIDDevice::processReadResult()
+{
+
+ OVR_ASSERT(ReadRequested);
+
+ DWORD bytesRead = 0;
+
+ if (GetOverlappedResult(Device, &ReadOverlapped, &bytesRead, FALSE))
+ {
+ // We've got data.
+ if (Handler)
+ {
+ Handler->OnInputReport(ReadBuffer, bytesRead);
+ }
+
+ // TBD: Not needed?
+ // Event should be reset by Read call...
+ ReadOverlapped.Pointer = 0;
+ ReadOverlapped.Internal = 0;
+ ReadOverlapped.InternalHigh = 0;
+ return true;
+ }
+ else
+ {
+ if (GetLastError() != ERROR_IO_PENDING)
+ {
+ closeDeviceOnIOError();
+ return false;
+ }
+ }
+
+ return false;
+}
+
+void HIDDevice::closeDevice()
+{
+ if (ReadRequested)
+ {
+ HIDManager->Manager->pThread->RemoveOverlappedEvent(this, ReadOverlapped.hEvent);
+ ReadRequested = false;
+ // Must call this to avoid Win32 assertion; CloseHandle is not enough.
+ ::CancelIo(Device);
+ }
+
+ ::CloseHandle(ReadOverlapped.hEvent);
+ memset(&ReadOverlapped, 0, sizeof(OVERLAPPED));
+
+ ::CloseHandle(Device);
+ Device = 0;
+}
+
+void HIDDevice::closeDeviceOnIOError()
+{
+ LogText("OVR::Win32::HIDDevice - Lost connection to '%s'\n", DevDesc.Path.ToCStr());
+ closeDevice();
+}
+
+bool HIDDevice::SetFeatureReport(UByte* data, UInt32 length)
+{
+ if (!ReadRequested)
+ return false;
+
+ return HIDManager->HidD_SetFeature(Device, data, (ULONG) length) != FALSE;
+}
+
+bool HIDDevice::GetFeatureReport(UByte* data, UInt32 length)
+{
+ if (!ReadRequested)
+ return false;
+
+ return HIDManager->HidD_GetFeature(Device, data, (ULONG) length) != FALSE;
+}
+
+void HIDDevice::OnOverlappedEvent(HANDLE hevent)
+{
+ OVR_UNUSED(hevent);
+ OVR_ASSERT(hevent == ReadOverlapped.hEvent);
+
+ if (processReadResult())
+ {
+ // Proceed to read again.
+ initializeRead();
+ }
+}
+
+UInt64 HIDDevice::OnTicks(UInt64 ticksMks)
+{
+ if (Handler)
+ {
+ return Handler->OnTicks(ticksMks);
+ }
+
+ return DeviceManagerThread::Notifier::OnTicks(ticksMks);
+}
+
+bool HIDDevice::OnDeviceMessage(DeviceMessageType messageType,
+ const String& devicePath,
+ bool* error)
+{
+
+ // Is this the correct device?
+ if (DevDesc.Path.CompareNoCase(devicePath) != 0)
+ {
+ return false;
+ }
+
+ if (messageType == DeviceMessage_DeviceAdded && !Device)
+ {
+ // A closed device has been re-added. Try to reopen.
+ if (!openDevice())
+ {
+ LogError("OVR::Win32::HIDDevice - Failed to reopen a device '%s' that was re-added.\n", devicePath.ToCStr());
+ *error = true;
+ return true;
+ }
+
+ LogText("OVR::Win32::HIDDevice - Reopened device '%s'\n", devicePath.ToCStr());
+ }
+
+ HIDHandler::HIDDeviceMessageType handlerMessageType = HIDHandler::HIDDeviceMessage_DeviceAdded;
+ if (messageType == DeviceMessage_DeviceAdded)
+ {
+ }
+ else if (messageType == DeviceMessage_DeviceRemoved)
+ {
+ handlerMessageType = HIDHandler::HIDDeviceMessage_DeviceRemoved;
+ }
+ else
+ {
+ OVR_ASSERT(0);
+ }
+
+ if (Handler)
+ {
+ Handler->OnDeviceMessage(handlerMessageType);
+ }
+
+ *error = false;
+ return true;
+}
+
+HIDDeviceManager* HIDDeviceManager::CreateInternal(Win32::DeviceManager* devManager)
+{
+
+ if (!System::IsInitialized())
+ {
+ // Use custom message, since Log is not yet installed.
+ OVR_DEBUG_STATEMENT(Log::GetDefaultLog()->
+ LogMessage(Log_Debug, "HIDDeviceManager::Create failed - OVR::System not initialized"); );
+ return 0;
+ }
+
+ Ptr<Win32::HIDDeviceManager> manager = *new Win32::HIDDeviceManager(devManager);
+
+ if (manager)
+ {
+ if (manager->Initialize())
+ {
+ manager->AddRef();
+ }
+ else
+ {
+ manager.Clear();
+ }
+ }
+
+ return manager.GetPtr();
+}
+
+} // namespace Win32
+
+//-------------------------------------------------------------------------------------
+// ***** Creation
+
+// Creates a new HIDDeviceManager and initializes OVR.
+HIDDeviceManager* HIDDeviceManager::Create()
+{
+ OVR_ASSERT_LOG(false, ("Standalone mode not implemented yet."));
+
+ if (!System::IsInitialized())
+ {
+ // Use custom message, since Log is not yet installed.
+ OVR_DEBUG_STATEMENT(Log::GetDefaultLog()->
+ LogMessage(Log_Debug, "HIDDeviceManager::Create failed - OVR::System not initialized"); );
+ return 0;
+ }
+
+ Ptr<Win32::HIDDeviceManager> manager = *new Win32::HIDDeviceManager(NULL);
+
+ if (manager)
+ {
+ if (manager->Initialize())
+ {
+ manager->AddRef();
+ }
+ else
+ {
+ manager.Clear();
+ }
+ }
+
+ return manager.GetPtr();
+}
+
+} // namespace OVR
diff --git a/LibOVR/Src/OVR_Win32_HIDDevice.h b/LibOVR/Src/OVR_Win32_HIDDevice.h
index efe308d..85a72e8 100644
--- a/LibOVR/Src/OVR_Win32_HIDDevice.h
+++ b/LibOVR/Src/OVR_Win32_HIDDevice.h
@@ -1,194 +1,194 @@
-/************************************************************************************
-
-Filename : OVR_Win32_HIDDevice.h
-Content : Win32 HID device implementation.
-Created : February 22, 2013
-Authors : Lee Cooper
-
-Copyright : Copyright 2013 Oculus VR, Inc. All Rights reserved.
-
-Use of this software is subject to the terms of the Oculus license
-agreement provided at the time of installation or download, or which
-otherwise accompanies this software in either electronic or hard copy form.
-
-*************************************************************************************/
-
-#ifndef OVR_Win32_HIDDevice_h
-#define OVR_Win32_HIDDevice_h
-
-#include "OVR_HIDDevice.h"
-#include "OVR_Win32_DeviceManager.h"
-
-#include <windows.h>
-#include <setupapi.h>
-
-//-------------------------------------------------------------------------------------
-// Define needed "hidsdi.h" functionality to avoid requiring DDK installation.
-// #include "hidsdi.h"
-
-#ifndef _HIDSDI_H
-#define _HIDSDI_H
-#include <pshpack4.h>
-
-#define HIDP_STATUS_SUCCESS (0x11 << 16)
-struct HIDP_PREPARSED_DATA;
-
-struct HIDD_ATTRIBUTES
-{
- ULONG Size; // = sizeof (struct _HIDD_ATTRIBUTES)
- USHORT VendorID;
- USHORT ProductID;
- USHORT VersionNumber;
-};
-
-struct HIDP_CAPS
-{
- USHORT Usage;
- USHORT UsagePage;
- USHORT InputReportByteLength;
- USHORT OutputReportByteLength;
- USHORT FeatureReportByteLength;
- USHORT Reserved[17];
-
- USHORT NumberLinkCollectionNodes;
- USHORT NumberInputButtonCaps;
- USHORT NumberInputValueCaps;
- USHORT NumberInputDataIndices;
- USHORT NumberOutputButtonCaps;
- USHORT NumberOutputValueCaps;
- USHORT NumberOutputDataIndices;
- USHORT NumberFeatureButtonCaps;
- USHORT NumberFeatureValueCaps;
- USHORT NumberFeatureDataIndices;
-};
-
-#include <poppack.h>
-#endif
-
-
-namespace OVR { namespace Win32 {
-
-class HIDDeviceManager;
-class DeviceManager;
-
-//-------------------------------------------------------------------------------------
-// ***** Win32 HIDDevice
-
-class HIDDevice : public OVR::HIDDevice, public DeviceManagerThread::Notifier
-{
-public:
-
- HIDDevice(HIDDeviceManager* manager);
-
- // This is a minimal constructor used during enumeration for us to pass
- // a HIDDevice to the visit function (so that it can query feature reports).
- HIDDevice(HIDDeviceManager* manager, HANDLE device);
-
- ~HIDDevice();
-
- bool HIDInitialize(const String& path);
- void HIDShutdown();
-
- // OVR::HIDDevice
- bool SetFeatureReport(UByte* data, UInt32 length);
- bool GetFeatureReport(UByte* data, UInt32 length);
-
-
- // DeviceManagerThread::Notifier
- void OnOverlappedEvent(HANDLE hevent);
- UInt64 OnTicks(UInt64 ticksMks);
- bool OnDeviceMessage(DeviceMessageType messageType, const String& devicePath, bool* error);
-
-private:
- bool openDevice();
- bool initInfo();
- bool initializeRead();
- bool processReadResult();
- void closeDevice();
- void closeDeviceOnIOError();
-
- bool inMinimalMode;
- HIDDeviceManager* HIDManager;
- HANDLE Device;
- HIDDeviceDesc DevDesc;
-
- OVERLAPPED ReadOverlapped;
- bool ReadRequested;
-
- enum { ReadBufferSize = 96 };
- UByte ReadBuffer[ReadBufferSize];
-
- UInt16 InputReportBufferLength;
- UInt16 OutputReportBufferLength;
- UInt16 FeatureReportBufferLength;
-};
-
-//-------------------------------------------------------------------------------------
-// ***** Win32 HIDDeviceManager
-
-class HIDDeviceManager : public OVR::HIDDeviceManager
-{
- friend class HIDDevice;
-public:
-
- HIDDeviceManager(DeviceManager* manager);
- virtual ~HIDDeviceManager();
-
- virtual bool Initialize();
- virtual void Shutdown();
-
- virtual bool Enumerate(HIDEnumerateVisitor* enumVisitor);
- virtual OVR::HIDDevice* Open(const String& path);
-
- // Fills HIDDeviceDesc by using the path.
- // Returns 'true' if successful, 'false' otherwise.
- bool GetHIDDeviceDesc(const String& path, HIDDeviceDesc* pdevDesc) const;
-
- GUID GetHIDGuid() { return HidGuid; }
-
- static HIDDeviceManager* CreateInternal(DeviceManager* manager);
-
-private:
-
- DeviceManager* Manager; // Back pointer can just be a raw pointer.
-
- HMODULE hHidLib;
- GUID HidGuid;
-
- // Macros to declare and resolve needed functions from library.
-#define OVR_DECLARE_HIDFUNC(func, rettype, args) \
-typedef rettype (__stdcall *PFn_##func) args; \
-PFn_##func func;
-#define OVR_RESOLVE_HIDFUNC(func) \
-func = (PFn_##func)::GetProcAddress(hHidLib, #func)
-
- OVR_DECLARE_HIDFUNC(HidD_GetHidGuid, void, (GUID *hidGuid));
- OVR_DECLARE_HIDFUNC(HidD_SetNumInputBuffers, BOOLEAN, (HANDLE hidDev, ULONG numberBuffers));
- OVR_DECLARE_HIDFUNC(HidD_GetFeature, BOOLEAN, (HANDLE hidDev, PVOID buffer, ULONG bufferLength));
- OVR_DECLARE_HIDFUNC(HidD_SetFeature, BOOLEAN, (HANDLE hidDev, PVOID buffer, ULONG bufferLength));
- OVR_DECLARE_HIDFUNC(HidD_GetAttributes, BOOLEAN, (HANDLE hidDev, HIDD_ATTRIBUTES *attributes));
- OVR_DECLARE_HIDFUNC(HidD_GetManufacturerString, BOOLEAN, (HANDLE hidDev, PVOID buffer, ULONG bufferLength));
- OVR_DECLARE_HIDFUNC(HidD_GetProductString, BOOLEAN, (HANDLE hidDev, PVOID buffer, ULONG bufferLength));
- OVR_DECLARE_HIDFUNC(HidD_GetSerialNumberString, BOOLEAN, (HANDLE hidDev, PVOID buffer, ULONG bufferLength));
- OVR_DECLARE_HIDFUNC(HidD_GetPreparsedData, BOOLEAN, (HANDLE hidDev, HIDP_PREPARSED_DATA **preparsedData));
- OVR_DECLARE_HIDFUNC(HidD_FreePreparsedData, BOOLEAN, (HIDP_PREPARSED_DATA *preparsedData));
- OVR_DECLARE_HIDFUNC(HidP_GetCaps, NTSTATUS,(HIDP_PREPARSED_DATA *preparsedData, HIDP_CAPS* caps));
-
- HANDLE CreateHIDFile(const char* path, bool exclusiveAccess = true) const
- {
- return ::CreateFileA(path, GENERIC_WRITE|GENERIC_READ,
- (!exclusiveAccess) ? (FILE_SHARE_READ|FILE_SHARE_WRITE) : 0x0,
- NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, 0);
- }
-
- // Helper functions to fill in HIDDeviceDesc from open device handle.
- bool initVendorProductVersion(HANDLE hidDev, HIDDeviceDesc* desc) const;
- bool initUsage(HANDLE hidDev, HIDDeviceDesc* desc) const;
- void initStrings(HANDLE hidDev, HIDDeviceDesc* desc) const;
-
- bool getFullDesc(HANDLE hidDev, HIDDeviceDesc* desc) const;
-};
-
-}} // namespace OVR::Win32
-
-#endif // OVR_Win32_HIDDevice_h
+/************************************************************************************
+
+Filename : OVR_Win32_HIDDevice.h
+Content : Win32 HID device implementation.
+Created : February 22, 2013
+Authors : Lee Cooper
+
+Copyright : Copyright 2013 Oculus VR, Inc. All Rights reserved.
+
+Use of this software is subject to the terms of the Oculus license
+agreement provided at the time of installation or download, or which
+otherwise accompanies this software in either electronic or hard copy form.
+
+*************************************************************************************/
+
+#ifndef OVR_Win32_HIDDevice_h
+#define OVR_Win32_HIDDevice_h
+
+#include "OVR_HIDDevice.h"
+#include "OVR_Win32_DeviceManager.h"
+
+#include <windows.h>
+#include <setupapi.h>
+
+//-------------------------------------------------------------------------------------
+// Define needed "hidsdi.h" functionality to avoid requiring DDK installation.
+// #include "hidsdi.h"
+
+#ifndef _HIDSDI_H
+#define _HIDSDI_H
+#include <pshpack4.h>
+
+#define HIDP_STATUS_SUCCESS (0x11 << 16)
+struct HIDP_PREPARSED_DATA;
+
+struct HIDD_ATTRIBUTES
+{
+ ULONG Size; // = sizeof (struct _HIDD_ATTRIBUTES)
+ USHORT VendorID;
+ USHORT ProductID;
+ USHORT VersionNumber;
+};
+
+struct HIDP_CAPS
+{
+ USHORT Usage;
+ USHORT UsagePage;
+ USHORT InputReportByteLength;
+ USHORT OutputReportByteLength;
+ USHORT FeatureReportByteLength;
+ USHORT Reserved[17];
+
+ USHORT NumberLinkCollectionNodes;
+ USHORT NumberInputButtonCaps;
+ USHORT NumberInputValueCaps;
+ USHORT NumberInputDataIndices;
+ USHORT NumberOutputButtonCaps;
+ USHORT NumberOutputValueCaps;
+ USHORT NumberOutputDataIndices;
+ USHORT NumberFeatureButtonCaps;
+ USHORT NumberFeatureValueCaps;
+ USHORT NumberFeatureDataIndices;
+};
+
+#include <poppack.h>
+#endif
+
+
+namespace OVR { namespace Win32 {
+
+class HIDDeviceManager;
+class DeviceManager;
+
+//-------------------------------------------------------------------------------------
+// ***** Win32 HIDDevice
+
+class HIDDevice : public OVR::HIDDevice, public DeviceManagerThread::Notifier
+{
+public:
+
+ HIDDevice(HIDDeviceManager* manager);
+
+ // This is a minimal constructor used during enumeration for us to pass
+ // a HIDDevice to the visit function (so that it can query feature reports).
+ HIDDevice(HIDDeviceManager* manager, HANDLE device);
+
+ ~HIDDevice();
+
+ bool HIDInitialize(const String& path);
+ void HIDShutdown();
+
+ // OVR::HIDDevice
+ bool SetFeatureReport(UByte* data, UInt32 length);
+ bool GetFeatureReport(UByte* data, UInt32 length);
+
+
+ // DeviceManagerThread::Notifier
+ void OnOverlappedEvent(HANDLE hevent);
+ UInt64 OnTicks(UInt64 ticksMks);
+ bool OnDeviceMessage(DeviceMessageType messageType, const String& devicePath, bool* error);
+
+private:
+ bool openDevice();
+ bool initInfo();
+ bool initializeRead();
+ bool processReadResult();
+ void closeDevice();
+ void closeDeviceOnIOError();
+
+ bool inMinimalMode;
+ HIDDeviceManager* HIDManager;
+ HANDLE Device;
+ HIDDeviceDesc DevDesc;
+
+ OVERLAPPED ReadOverlapped;
+ bool ReadRequested;
+
+ enum { ReadBufferSize = 96 };
+ UByte ReadBuffer[ReadBufferSize];
+
+ UInt16 InputReportBufferLength;
+ UInt16 OutputReportBufferLength;
+ UInt16 FeatureReportBufferLength;
+};
+
+//-------------------------------------------------------------------------------------
+// ***** Win32 HIDDeviceManager
+
+class HIDDeviceManager : public OVR::HIDDeviceManager
+{
+ friend class HIDDevice;
+public:
+
+ HIDDeviceManager(DeviceManager* manager);
+ virtual ~HIDDeviceManager();
+
+ virtual bool Initialize();
+ virtual void Shutdown();
+
+ virtual bool Enumerate(HIDEnumerateVisitor* enumVisitor);
+ virtual OVR::HIDDevice* Open(const String& path);
+
+ // Fills HIDDeviceDesc by using the path.
+ // Returns 'true' if successful, 'false' otherwise.
+ bool GetHIDDeviceDesc(const String& path, HIDDeviceDesc* pdevDesc) const;
+
+ GUID GetHIDGuid() { return HidGuid; }
+
+ static HIDDeviceManager* CreateInternal(DeviceManager* manager);
+
+private:
+
+ DeviceManager* Manager; // Back pointer can just be a raw pointer.
+
+ HMODULE hHidLib;
+ GUID HidGuid;
+
+ // Macros to declare and resolve needed functions from library.
+#define OVR_DECLARE_HIDFUNC(func, rettype, args) \
+typedef rettype (__stdcall *PFn_##func) args; \
+PFn_##func func;
+#define OVR_RESOLVE_HIDFUNC(func) \
+func = (PFn_##func)::GetProcAddress(hHidLib, #func)
+
+ OVR_DECLARE_HIDFUNC(HidD_GetHidGuid, void, (GUID *hidGuid));
+ OVR_DECLARE_HIDFUNC(HidD_SetNumInputBuffers, BOOLEAN, (HANDLE hidDev, ULONG numberBuffers));
+ OVR_DECLARE_HIDFUNC(HidD_GetFeature, BOOLEAN, (HANDLE hidDev, PVOID buffer, ULONG bufferLength));
+ OVR_DECLARE_HIDFUNC(HidD_SetFeature, BOOLEAN, (HANDLE hidDev, PVOID buffer, ULONG bufferLength));
+ OVR_DECLARE_HIDFUNC(HidD_GetAttributes, BOOLEAN, (HANDLE hidDev, HIDD_ATTRIBUTES *attributes));
+ OVR_DECLARE_HIDFUNC(HidD_GetManufacturerString, BOOLEAN, (HANDLE hidDev, PVOID buffer, ULONG bufferLength));
+ OVR_DECLARE_HIDFUNC(HidD_GetProductString, BOOLEAN, (HANDLE hidDev, PVOID buffer, ULONG bufferLength));
+ OVR_DECLARE_HIDFUNC(HidD_GetSerialNumberString, BOOLEAN, (HANDLE hidDev, PVOID buffer, ULONG bufferLength));
+ OVR_DECLARE_HIDFUNC(HidD_GetPreparsedData, BOOLEAN, (HANDLE hidDev, HIDP_PREPARSED_DATA **preparsedData));
+ OVR_DECLARE_HIDFUNC(HidD_FreePreparsedData, BOOLEAN, (HIDP_PREPARSED_DATA *preparsedData));
+ OVR_DECLARE_HIDFUNC(HidP_GetCaps, NTSTATUS,(HIDP_PREPARSED_DATA *preparsedData, HIDP_CAPS* caps));
+
+ HANDLE CreateHIDFile(const char* path, bool exclusiveAccess = true) const
+ {
+ return ::CreateFileA(path, GENERIC_WRITE|GENERIC_READ,
+ (!exclusiveAccess) ? (FILE_SHARE_READ|FILE_SHARE_WRITE) : 0x0,
+ NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, 0);
+ }
+
+ // Helper functions to fill in HIDDeviceDesc from open device handle.
+ bool initVendorProductVersion(HANDLE hidDev, HIDDeviceDesc* desc) const;
+ bool initUsage(HANDLE hidDev, HIDDeviceDesc* desc) const;
+ void initStrings(HANDLE hidDev, HIDDeviceDesc* desc) const;
+
+ bool getFullDesc(HANDLE hidDev, HIDDeviceDesc* desc) const;
+};
+
+}} // namespace OVR::Win32
+
+#endif // OVR_Win32_HIDDevice_h
diff --git a/LibOVR/Src/OVR_Win32_HMDDevice.cpp b/LibOVR/Src/OVR_Win32_HMDDevice.cpp
index 095d3a8..09bddbf 100644
--- a/LibOVR/Src/OVR_Win32_HMDDevice.cpp
+++ b/LibOVR/Src/OVR_Win32_HMDDevice.cpp
@@ -1,418 +1,498 @@
-/************************************************************************************
-
-Filename : OVR_Win32_HMDDevice.cpp
-Content : Win32 Interface to HMD - detects HMD display
-Created : September 21, 2012
-Authors : Michael Antonov
-
-Copyright : Copyright 2012 Oculus VR, Inc. All Rights reserved.
-
-Use of this software is subject to the terms of the Oculus license
-agreement provided at the time of installation or download, or which
-otherwise accompanies this software in either electronic or hard copy form.
-
-*************************************************************************************/
-
-#include "OVR_Win32_HMDDevice.h"
-
-#include "OVR_Win32_DeviceManager.h"
-
-#include <tchar.h>
-
-namespace OVR { namespace Win32 {
-
-//-------------------------------------------------------------------------------------
-
-HMDDeviceCreateDesc::HMDDeviceCreateDesc(DeviceFactory* factory,
- const String& deviceId, const String& displayDeviceName)
- : DeviceCreateDesc(factory, Device_HMD),
- DeviceId(deviceId), DisplayDeviceName(displayDeviceName),
- DesktopX(0), DesktopY(0), Contents(0),
- HResolution(0), VResolution(0), HScreenSize(0), VScreenSize(0)
-{
-}
-HMDDeviceCreateDesc::HMDDeviceCreateDesc(const HMDDeviceCreateDesc& other)
- : DeviceCreateDesc(other.pFactory, Device_HMD),
- DeviceId(other.DeviceId), DisplayDeviceName(other.DisplayDeviceName),
- DesktopX(other.DesktopX), DesktopY(other.DesktopY), Contents(other.Contents),
- HResolution(other.HResolution), VResolution(other.VResolution),
- HScreenSize(other.HScreenSize), VScreenSize(other.VScreenSize)
-{
-}
-
-HMDDeviceCreateDesc::MatchResult HMDDeviceCreateDesc::MatchDevice(const DeviceCreateDesc& other,
- DeviceCreateDesc** pcandidate) const
-{
- if ((other.Type != Device_HMD) || (other.pFactory != pFactory))
- return Match_None;
-
- // There are several reasons we can come in here:
- // a) Matching this HMD Monitor created desc to OTHER HMD Monitor desc
- // - Require exact device DeviceId/DeviceName match
- // b) Matching SensorDisplayInfo created desc to OTHER HMD Monitor desc
- // - This DeviceId is empty; becomes candidate
- // c) Matching this HMD Monitor created desc to SensorDisplayInfo desc
- // - This other.DeviceId is empty; becomes candidate
-
- const HMDDeviceCreateDesc& s2 = (const HMDDeviceCreateDesc&) other;
-
- if ((DeviceId == s2.DeviceId) &&
- (DisplayDeviceName == s2.DisplayDeviceName))
- {
- // Non-null DeviceId may match while size is different if screen size was overwritten
- // by SensorDisplayInfo in prior iteration.
- if (!DeviceId.IsEmpty() ||
- ((HScreenSize == s2.HScreenSize) &&
- (VScreenSize == s2.VScreenSize)) )
- {
- *pcandidate = 0;
- return Match_Found;
- }
- }
-
-
- // DisplayInfo takes precedence, although we try to match it first.
- if ((HResolution == s2.HResolution) &&
- (VResolution == s2.VResolution) &&
- (HScreenSize == s2.HScreenSize) &&
- (VScreenSize == s2.VScreenSize))
- {
- if (DeviceId.IsEmpty() && !s2.DeviceId.IsEmpty())
- {
- *pcandidate = const_cast<DeviceCreateDesc*>((const DeviceCreateDesc*)this);
- return Match_Candidate;
- }
-
- *pcandidate = 0;
- return Match_Found;
- }
-
- // SensorDisplayInfo may override resolution settings, so store as candidate.
- if (s2.DeviceId.IsEmpty())
- {
- *pcandidate = const_cast<DeviceCreateDesc*>((const DeviceCreateDesc*)this);
- return Match_Candidate;
- }
- // OTHER HMD Monitor desc may initialize DeviceName/Id
- else if (DeviceId.IsEmpty())
- {
- *pcandidate = const_cast<DeviceCreateDesc*>((const DeviceCreateDesc*)this);
- return Match_Candidate;
- }
-
- return Match_None;
-}
-
-
-bool HMDDeviceCreateDesc::UpdateMatchedCandidate(const DeviceCreateDesc& other,
- bool* newDeviceFlag)
-{
- // This candidate was the the "best fit" to apply sensor DisplayInfo to.
- OVR_ASSERT(other.Type == Device_HMD);
-
- const HMDDeviceCreateDesc& s2 = (const HMDDeviceCreateDesc&) other;
-
- // Force screen size on resolution from SensorDisplayInfo.
- // We do this because USB detection is more reliable as compared to HDMI EDID,
- // which may be corrupted by splitter reporting wrong monitor
- if (s2.DeviceId.IsEmpty())
- {
- HScreenSize = s2.HScreenSize;
- VScreenSize = s2.VScreenSize;
- Contents |= Contents_Screen;
-
- if (s2.Contents & HMDDeviceCreateDesc::Contents_Distortion)
- {
- memcpy(DistortionK, s2.DistortionK, sizeof(float)*4);
- Contents |= Contents_Distortion;
- }
- DeviceId = s2.DeviceId;
- DisplayDeviceName = s2.DisplayDeviceName;
- if (newDeviceFlag) *newDeviceFlag = true;
- }
- else if (DeviceId.IsEmpty())
- {
- DeviceId = s2.DeviceId;
- DisplayDeviceName = s2.DisplayDeviceName;
- if (newDeviceFlag) *newDeviceFlag = true;
- }
- else
- {
- if (newDeviceFlag) *newDeviceFlag = false;
- }
-
- return true;
-}
-
-bool HMDDeviceCreateDesc::MatchDevice(const String& path)
-{
- return DeviceId.CompareNoCase(path) == 0;
-}
-
-//-------------------------------------------------------------------------------------
-
-
-const wchar_t* FormatDisplayStateFlags(wchar_t* buff, int length, DWORD flags)
-{
- buff[0] = 0;
- if (flags & DISPLAY_DEVICE_ACTIVE)
- wcscat_s(buff, length, L"Active ");
- if (flags & DISPLAY_DEVICE_MIRRORING_DRIVER)
- wcscat_s(buff, length, L"Mirroring_Driver ");
- if (flags & DISPLAY_DEVICE_MODESPRUNED)
- wcscat_s(buff, length, L"ModesPruned ");
- if (flags & DISPLAY_DEVICE_PRIMARY_DEVICE)
- wcscat_s(buff, length, L"Primary ");
- if (flags & DISPLAY_DEVICE_REMOVABLE)
- wcscat_s(buff, length, L"Removable ");
- if (flags & DISPLAY_DEVICE_VGA_COMPATIBLE)
- wcscat_s(buff, length, L"VGA_Compatible ");
- return buff;
-}
-
-
-//-------------------------------------------------------------------------------------
-// Callback for monitor enumeration to store all the monitor handles
-
-// Used to capture all the active monitor handles
-struct MonitorSet
-{
- enum { MaxMonitors = 8 };
- HMONITOR Monitors[MaxMonitors];
- int MonitorCount;
-};
-
-BOOL CALLBACK MonitorEnumProc(HMONITOR hMonitor, HDC, LPRECT, LPARAM dwData)
-{
- MonitorSet* monitorSet = (MonitorSet*)dwData;
- if (monitorSet->MonitorCount > MonitorSet::MaxMonitors)
- return FALSE;
-
- monitorSet->Monitors[monitorSet->MonitorCount] = hMonitor;
- monitorSet->MonitorCount++;
- return TRUE;
-};
-
-//-------------------------------------------------------------------------------------
-// ***** HMDDeviceFactory
-
-HMDDeviceFactory HMDDeviceFactory::Instance;
-
-void HMDDeviceFactory::EnumerateDevices(EnumerateVisitor& visitor)
-{
- MonitorSet monitors;
- monitors.MonitorCount = 0;
- // Get all the monitor handles
- EnumDisplayMonitors(NULL, NULL, MonitorEnumProc, (LPARAM)&monitors);
-
- bool foundHMD = false;
-
- // DeviceManager* manager = getManager();
- DISPLAY_DEVICE dd, ddm;
- UINT i, j;
-
- for (i = 0;
- (ZeroMemory(&dd, sizeof(dd)), dd.cb = sizeof(dd),
- EnumDisplayDevices(0, i, &dd, 0)) != 0; i++)
- {
-
- /*
- wchar_t buff[500], flagsBuff[200];
-
- swprintf_s(buff, 500, L"\nDEV: \"%s\" \"%s\" 0x%08x=%s\n \"%s\" \"%s\"\n",
- dd.DeviceName, dd.DeviceString,
- dd.StateFlags, FormatDisplayStateFlags(flagsBuff, 200, dd.StateFlags),
- dd.DeviceID, dd.DeviceKey);
- ::OutputDebugString(buff);
- */
-
- for (j = 0;
- (ZeroMemory(&ddm, sizeof(ddm)), ddm.cb = sizeof(ddm),
- EnumDisplayDevices(dd.DeviceName, j, &ddm, 0)) != 0; j++)
- {
- /*
- wchar_t mbuff[500];
- swprintf_s(mbuff, 500, L"MON: \"%s\" \"%s\" 0x%08x=%s\n \"%s\" \"%s\"\n",
- ddm.DeviceName, ddm.DeviceString,
- ddm.StateFlags, FormatDisplayStateFlags(flagsBuff, 200, ddm.StateFlags),
- ddm.DeviceID, ddm.DeviceKey);
- ::OutputDebugString(mbuff);
- */
-
- // Our monitor hardware has string "RTD2205" in it
- // Nate's device "CVT0003"
- if (wcsstr(ddm.DeviceID, L"RTD2205") ||
- wcsstr(ddm.DeviceID, L"CVT0003") ||
- wcsstr(ddm.DeviceID, L"MST0030") ||
- wcsstr(ddm.DeviceID, L"OVR00") ) // Part of Oculus EDID.
- {
- String deviceId(ddm.DeviceID);
- String displayDeviceName(ddm.DeviceName);
-
- // The default monitor coordinates
- int mx = 0;
- int my = 0;
- int mwidth = 1280;
- int mheight = 800;
-
- // Find the matching MONITORINFOEX for this device so we can get the
- // screen coordinates
- MONITORINFOEX info;
- for (int m=0; m < monitors.MonitorCount; m++)
- {
- info.cbSize = sizeof(MONITORINFOEX);
- GetMonitorInfo(monitors.Monitors[m], &info);
- if (_tcsstr(ddm.DeviceName, info.szDevice) == ddm.DeviceName)
- { // If the device name starts with the monitor name
- // then we found the matching DISPLAY_DEVICE and MONITORINFO
- // so we can gather the monitor coordinates
- mx = info.rcMonitor.left;
- my = info.rcMonitor.top;
- //mwidth = info.rcMonitor.right - info.rcMonitor.left;
- //mheight = info.rcMonitor.bottom - info.rcMonitor.top;
- break;
- }
- }
-
- HMDDeviceCreateDesc hmdCreateDesc(this, deviceId, displayDeviceName);
-
- if (hmdCreateDesc.Is7Inch())
- {
- // Physical dimension of SLA screen.
- hmdCreateDesc.SetScreenParameters(mx, my, mwidth, mheight, 0.14976f, 0.0936f);
- }
- else
- {
- hmdCreateDesc.SetScreenParameters(mx, my, mwidth, mheight, 0.12096f, 0.0756f);
- }
-
- OVR_DEBUG_LOG_TEXT(("DeviceManager - HMD Found %s - %s\n",
- deviceId.ToCStr(), displayDeviceName.ToCStr()));
-
- // Notify caller about detected device. This will call EnumerateAddDevice
- // if the this is the first time device was detected.
- visitor.Visit(hmdCreateDesc);
- foundHMD = true;
- break;
- }
- }
- }
-
- // Real HMD device is not found; however, we still may have a 'fake' HMD
- // device created via SensorDeviceImpl::EnumerateHMDFromSensorDisplayInfo.
- // Need to find it and set 'Enumerated' to true to avoid Removal notification.
- if (!foundHMD)
- {
- Ptr<DeviceCreateDesc> hmdDevDesc = getManager()->FindDevice("", Device_HMD);
- if (hmdDevDesc)
- hmdDevDesc->Enumerated = true;
- }
-}
-
-DeviceBase* HMDDeviceCreateDesc::NewDeviceInstance()
-{
- return new HMDDevice(this);
-}
-
-bool HMDDeviceCreateDesc::Is7Inch() const
-{
- return (strstr(DeviceId.ToCStr(), "OVR0001") != 0) || (Contents & Contents_7Inch);
-}
-
-bool HMDDeviceCreateDesc::GetDeviceInfo(DeviceInfo* info) const
-{
- if ((info->InfoClassType != Device_HMD) &&
- (info->InfoClassType != Device_None))
- return false;
-
- bool is7Inch = Is7Inch();
-
- OVR_strcpy(info->ProductName, DeviceInfo::MaxNameLength,
- is7Inch ? "Oculus Rift DK1" : "Oculus Rift DK1-Prototype");
- OVR_strcpy(info->Manufacturer, DeviceInfo::MaxNameLength, "Oculus VR");
- info->Type = Device_HMD;
- info->Version = 0;
-
- // Display detection.
- if (info->InfoClassType == Device_HMD)
- {
- HMDInfo* hmdInfo = static_cast<HMDInfo*>(info);
-
- hmdInfo->DesktopX = DesktopX;
- hmdInfo->DesktopY = DesktopY;
- hmdInfo->HResolution = HResolution;
- hmdInfo->VResolution = VResolution;
- hmdInfo->HScreenSize = HScreenSize;
- hmdInfo->VScreenSize = VScreenSize;
- hmdInfo->VScreenCenter = VScreenSize * 0.5f;
- hmdInfo->InterpupillaryDistance = 0.064f; // Default IPD; should be configurable.
- hmdInfo->LensSeparationDistance = 0.0635f;
-
- if (Contents & Contents_Distortion)
- {
- memcpy(hmdInfo->DistortionK, DistortionK, sizeof(float)*4);
- }
- else
- {
- if (is7Inch)
- {
- // 7" screen.
- hmdInfo->DistortionK[0] = 1.0f;
- hmdInfo->DistortionK[1] = 0.22f;
- hmdInfo->DistortionK[2] = 0.24f;
- hmdInfo->EyeToScreenDistance = 0.041f;
-
- hmdInfo->ChromaAbCorrection[0] = 0.996f;
- hmdInfo->ChromaAbCorrection[1] = -0.004f;
- hmdInfo->ChromaAbCorrection[2] = 1.014f;
- hmdInfo->ChromaAbCorrection[3] = 0.0f;
- }
- else
- {
- hmdInfo->DistortionK[0] = 1.0f;
- hmdInfo->DistortionK[1] = 0.18f;
- hmdInfo->DistortionK[2] = 0.115f;
- hmdInfo->EyeToScreenDistance = 0.0387f;
- }
- }
-
- OVR_strcpy(hmdInfo->DisplayDeviceName, sizeof(hmdInfo->DisplayDeviceName),
- DisplayDeviceName.ToCStr());
- }
-
- return true;
-}
-
-//-------------------------------------------------------------------------------------
-// ***** HMDDevice
-
-HMDDevice::HMDDevice(HMDDeviceCreateDesc* createDesc)
- : OVR::DeviceImpl<OVR::HMDDevice>(createDesc, 0)
-{
-}
-HMDDevice::~HMDDevice()
-{
-}
-
-bool HMDDevice::Initialize(DeviceBase* parent)
-{
- pParent = parent;
- return true;
-}
-void HMDDevice::Shutdown()
-{
- pParent.Clear();
-}
-
-OVR::SensorDevice* HMDDevice::GetSensor()
-{
- // Just return first sensor found since we have no way to match it yet.
- OVR::SensorDevice* sensor = GetManager()->EnumerateDevices<SensorDevice>().CreateDevice();
- if (sensor)
- sensor->SetCoordinateFrame(SensorDevice::Coord_HMD);
- return sensor;
-}
-
-}} // namespace OVR::Win32
-
-
+/************************************************************************************
+
+Filename : OVR_Win32_HMDDevice.cpp
+Content : Win32 Interface to HMD - detects HMD display
+Created : September 21, 2012
+Authors : Michael Antonov
+
+Copyright : Copyright 2012 Oculus VR, Inc. All Rights reserved.
+
+Use of this software is subject to the terms of the Oculus license
+agreement provided at the time of installation or download, or which
+otherwise accompanies this software in either electronic or hard copy form.
+
+*************************************************************************************/
+
+#include "OVR_Win32_HMDDevice.h"
+
+#include "OVR_Win32_DeviceManager.h"
+
+#include <tchar.h>
+
+namespace OVR { namespace Win32 {
+
+//-------------------------------------------------------------------------------------
+
+HMDDeviceCreateDesc::HMDDeviceCreateDesc(DeviceFactory* factory,
+ const String& deviceId, const String& displayDeviceName)
+ : DeviceCreateDesc(factory, Device_HMD),
+ DeviceId(deviceId), DisplayDeviceName(displayDeviceName),
+ DesktopX(0), DesktopY(0), Contents(0),
+ HResolution(0), VResolution(0), HScreenSize(0), VScreenSize(0)
+{
+}
+HMDDeviceCreateDesc::HMDDeviceCreateDesc(const HMDDeviceCreateDesc& other)
+ : DeviceCreateDesc(other.pFactory, Device_HMD),
+ DeviceId(other.DeviceId), DisplayDeviceName(other.DisplayDeviceName),
+ DesktopX(other.DesktopX), DesktopY(other.DesktopY), Contents(other.Contents),
+ HResolution(other.HResolution), VResolution(other.VResolution),
+ HScreenSize(other.HScreenSize), VScreenSize(other.VScreenSize)
+{
+}
+
+HMDDeviceCreateDesc::MatchResult HMDDeviceCreateDesc::MatchDevice(const DeviceCreateDesc& other,
+ DeviceCreateDesc** pcandidate) const
+{
+ if ((other.Type != Device_HMD) || (other.pFactory != pFactory))
+ return Match_None;
+
+ // There are several reasons we can come in here:
+ // a) Matching this HMD Monitor created desc to OTHER HMD Monitor desc
+ // - Require exact device DeviceId/DeviceName match
+ // b) Matching SensorDisplayInfo created desc to OTHER HMD Monitor desc
+ // - This DeviceId is empty; becomes candidate
+ // c) Matching this HMD Monitor created desc to SensorDisplayInfo desc
+ // - This other.DeviceId is empty; becomes candidate
+
+ const HMDDeviceCreateDesc& s2 = (const HMDDeviceCreateDesc&) other;
+
+ if ((DeviceId == s2.DeviceId) &&
+ (DisplayDeviceName == s2.DisplayDeviceName))
+ {
+ // Non-null DeviceId may match while size is different if screen size was overwritten
+ // by SensorDisplayInfo in prior iteration.
+ if (!DeviceId.IsEmpty() ||
+ ((HScreenSize == s2.HScreenSize) &&
+ (VScreenSize == s2.VScreenSize)) )
+ {
+ *pcandidate = 0;
+ return Match_Found;
+ }
+ }
+
+
+ // DisplayInfo takes precedence, although we try to match it first.
+ if ((HResolution == s2.HResolution) &&
+ (VResolution == s2.VResolution) &&
+ (HScreenSize == s2.HScreenSize) &&
+ (VScreenSize == s2.VScreenSize))
+ {
+ if (DeviceId.IsEmpty() && !s2.DeviceId.IsEmpty())
+ {
+ *pcandidate = const_cast<DeviceCreateDesc*>((const DeviceCreateDesc*)this);
+ return Match_Candidate;
+ }
+
+ *pcandidate = 0;
+ return Match_Found;
+ }
+
+ // SensorDisplayInfo may override resolution settings, so store as candidate.
+ if (s2.DeviceId.IsEmpty())
+ {
+ *pcandidate = const_cast<DeviceCreateDesc*>((const DeviceCreateDesc*)this);
+ return Match_Candidate;
+ }
+ // OTHER HMD Monitor desc may initialize DeviceName/Id
+ else if (DeviceId.IsEmpty())
+ {
+ *pcandidate = const_cast<DeviceCreateDesc*>((const DeviceCreateDesc*)this);
+ return Match_Candidate;
+ }
+
+ return Match_None;
+}
+
+
+bool HMDDeviceCreateDesc::UpdateMatchedCandidate(const DeviceCreateDesc& other,
+ bool* newDeviceFlag)
+{
+ // This candidate was the the "best fit" to apply sensor DisplayInfo to.
+ OVR_ASSERT(other.Type == Device_HMD);
+
+ const HMDDeviceCreateDesc& s2 = (const HMDDeviceCreateDesc&) other;
+
+ // Force screen size on resolution from SensorDisplayInfo.
+ // We do this because USB detection is more reliable as compared to HDMI EDID,
+ // which may be corrupted by splitter reporting wrong monitor
+ if (s2.DeviceId.IsEmpty())
+ {
+ HScreenSize = s2.HScreenSize;
+ VScreenSize = s2.VScreenSize;
+ Contents |= Contents_Screen;
+
+ if (s2.Contents & HMDDeviceCreateDesc::Contents_Distortion)
+ {
+ memcpy(DistortionK, s2.DistortionK, sizeof(float)*4);
+ Contents |= Contents_Distortion;
+ }
+ DeviceId = s2.DeviceId;
+ DisplayDeviceName = s2.DisplayDeviceName;
+ DesktopX = s2.DesktopX;
+ DesktopY = s2.DesktopY;
+ if (newDeviceFlag) *newDeviceFlag = true;
+ }
+ else if (DeviceId.IsEmpty())
+ {
+ DeviceId = s2.DeviceId;
+ DisplayDeviceName = s2.DisplayDeviceName;
+ DesktopX = s2.DesktopX;
+ DesktopY = s2.DesktopY;
+
+ // ScreenSize and Resolution are NOT assigned here, since they may have
+ // come from a sensor DisplayInfo (which has precedence over HDMI).
+
+ if (newDeviceFlag) *newDeviceFlag = true;
+ }
+ else
+ {
+ if (newDeviceFlag) *newDeviceFlag = false;
+ }
+
+ return true;
+}
+
+bool HMDDeviceCreateDesc::MatchDevice(const String& path)
+{
+ return DeviceId.CompareNoCase(path) == 0;
+}
+
+//-------------------------------------------------------------------------------------
+
+
+const wchar_t* FormatDisplayStateFlags(wchar_t* buff, int length, DWORD flags)
+{
+ buff[0] = 0;
+ if (flags & DISPLAY_DEVICE_ACTIVE)
+ wcscat_s(buff, length, L"Active ");
+ if (flags & DISPLAY_DEVICE_MIRRORING_DRIVER)
+ wcscat_s(buff, length, L"Mirroring_Driver ");
+ if (flags & DISPLAY_DEVICE_MODESPRUNED)
+ wcscat_s(buff, length, L"ModesPruned ");
+ if (flags & DISPLAY_DEVICE_PRIMARY_DEVICE)
+ wcscat_s(buff, length, L"Primary ");
+ if (flags & DISPLAY_DEVICE_REMOVABLE)
+ wcscat_s(buff, length, L"Removable ");
+ if (flags & DISPLAY_DEVICE_VGA_COMPATIBLE)
+ wcscat_s(buff, length, L"VGA_Compatible ");
+ return buff;
+}
+
+
+//-------------------------------------------------------------------------------------
+// Callback for monitor enumeration to store all the monitor handles
+
+// Used to capture all the active monitor handles
+struct MonitorSet
+{
+ enum { MaxMonitors = 8 };
+ HMONITOR Monitors[MaxMonitors];
+ int MonitorCount;
+};
+
+BOOL CALLBACK MonitorEnumProc(HMONITOR hMonitor, HDC, LPRECT, LPARAM dwData)
+{
+ MonitorSet* monitorSet = (MonitorSet*)dwData;
+ if (monitorSet->MonitorCount > MonitorSet::MaxMonitors)
+ return FALSE;
+
+ monitorSet->Monitors[monitorSet->MonitorCount] = hMonitor;
+ monitorSet->MonitorCount++;
+ return TRUE;
+};
+
+//-------------------------------------------------------------------------------------
+// ***** HMDDeviceFactory
+
+HMDDeviceFactory HMDDeviceFactory::Instance;
+
+void HMDDeviceFactory::EnumerateDevices(EnumerateVisitor& visitor)
+{
+ MonitorSet monitors;
+ monitors.MonitorCount = 0;
+ // Get all the monitor handles
+ EnumDisplayMonitors(NULL, NULL, MonitorEnumProc, (LPARAM)&monitors);
+
+ bool foundHMD = false;
+
+ // DeviceManager* manager = getManager();
+ DISPLAY_DEVICE dd, ddm;
+ UINT i, j;
+
+ for (i = 0;
+ (ZeroMemory(&dd, sizeof(dd)), dd.cb = sizeof(dd),
+ EnumDisplayDevices(0, i, &dd, 0)) != 0; i++)
+ {
+
+ /*
+ wchar_t buff[500], flagsBuff[200];
+
+ swprintf_s(buff, 500, L"\nDEV: \"%s\" \"%s\" 0x%08x=%s\n \"%s\" \"%s\"\n",
+ dd.DeviceName, dd.DeviceString,
+ dd.StateFlags, FormatDisplayStateFlags(flagsBuff, 200, dd.StateFlags),
+ dd.DeviceID, dd.DeviceKey);
+ ::OutputDebugString(buff);
+ */
+
+ for (j = 0;
+ (ZeroMemory(&ddm, sizeof(ddm)), ddm.cb = sizeof(ddm),
+ EnumDisplayDevices(dd.DeviceName, j, &ddm, 0)) != 0; j++)
+ {
+ /*
+ wchar_t mbuff[500];
+ swprintf_s(mbuff, 500, L"MON: \"%s\" \"%s\" 0x%08x=%s\n \"%s\" \"%s\"\n",
+ ddm.DeviceName, ddm.DeviceString,
+ ddm.StateFlags, FormatDisplayStateFlags(flagsBuff, 200, ddm.StateFlags),
+ ddm.DeviceID, ddm.DeviceKey);
+ ::OutputDebugString(mbuff);
+ */
+
+ // Our monitor hardware has string "RTD2205" in it
+ // Nate's device "CVT0003"
+ if (wcsstr(ddm.DeviceID, L"RTD2205") ||
+ wcsstr(ddm.DeviceID, L"CVT0003") ||
+ wcsstr(ddm.DeviceID, L"MST0030") ||
+ wcsstr(ddm.DeviceID, L"OVR00") ) // Part of Oculus EDID.
+ {
+ String deviceId(ddm.DeviceID);
+ String displayDeviceName(ddm.DeviceName);
+
+ // The default monitor coordinates
+ int mx = 0;
+ int my = 0;
+ int mwidth = 1280;
+ int mheight = 800;
+
+ // Find the matching MONITORINFOEX for this device so we can get the
+ // screen coordinates
+ MONITORINFOEX info;
+ for (int m=0; m < monitors.MonitorCount; m++)
+ {
+ info.cbSize = sizeof(MONITORINFOEX);
+ GetMonitorInfo(monitors.Monitors[m], &info);
+ if (_tcsstr(ddm.DeviceName, info.szDevice) == ddm.DeviceName)
+ { // If the device name starts with the monitor name
+ // then we found the matching DISPLAY_DEVICE and MONITORINFO
+ // so we can gather the monitor coordinates
+ mx = info.rcMonitor.left;
+ my = info.rcMonitor.top;
+ //mwidth = info.rcMonitor.right - info.rcMonitor.left;
+ //mheight = info.rcMonitor.bottom - info.rcMonitor.top;
+ break;
+ }
+ }
+
+ HMDDeviceCreateDesc hmdCreateDesc(this, deviceId, displayDeviceName);
+
+ if (wcsstr(ddm.DeviceID, L"OVR0002"))
+ {
+ hmdCreateDesc.SetScreenParameters(mx, my, 1920, 1080, 0.12096f, 0.06804f);
+ }
+ else
+ {
+ if (hmdCreateDesc.Is7Inch())
+ {
+ // Physical dimension of SLA screen.
+ hmdCreateDesc.SetScreenParameters(mx, my, mwidth, mheight, 0.14976f, 0.0936f);
+ }
+ else
+ {
+ hmdCreateDesc.SetScreenParameters(mx, my, mwidth, mheight, 0.12096f, 0.0756f);
+ }
+ }
+
+
+ OVR_DEBUG_LOG_TEXT(("DeviceManager - HMD Found %s - %s\n",
+ deviceId.ToCStr(), displayDeviceName.ToCStr()));
+
+ // Notify caller about detected device. This will call EnumerateAddDevice
+ // if the this is the first time device was detected.
+ visitor.Visit(hmdCreateDesc);
+ foundHMD = true;
+ break;
+ }
+ }
+ }
+
+ // Real HMD device is not found; however, we still may have a 'fake' HMD
+ // device created via SensorDeviceImpl::EnumerateHMDFromSensorDisplayInfo.
+ // Need to find it and set 'Enumerated' to true to avoid Removal notification.
+ if (!foundHMD)
+ {
+ Ptr<DeviceCreateDesc> hmdDevDesc = getManager()->FindDevice("", Device_HMD);
+ if (hmdDevDesc)
+ hmdDevDesc->Enumerated = true;
+ }
+}
+
+DeviceBase* HMDDeviceCreateDesc::NewDeviceInstance()
+{
+ return new HMDDevice(this);
+}
+
+bool HMDDeviceCreateDesc::Is7Inch() const
+{
+ return (strstr(DeviceId.ToCStr(), "OVR0001") != 0) || (Contents & Contents_7Inch);
+}
+
+Profile* HMDDeviceCreateDesc::GetProfileAddRef() const
+{
+ // Create device may override profile name, so get it from there is possible.
+ ProfileManager* profileManager = GetManagerImpl()->GetProfileManager();
+ ProfileType profileType = GetProfileType();
+ const char * profileName = pDevice ?
+ ((HMDDevice*)pDevice)->GetProfileName() :
+ profileManager->GetDefaultProfileName(profileType);
+
+ return profileName ?
+ profileManager->LoadProfile(profileType, profileName) :
+ profileManager->GetDeviceDefaultProfile(profileType);
+}
+
+
+bool HMDDeviceCreateDesc::GetDeviceInfo(DeviceInfo* info) const
+{
+ if ((info->InfoClassType != Device_HMD) &&
+ (info->InfoClassType != Device_None))
+ return false;
+
+ bool is7Inch = Is7Inch();
+
+ OVR_strcpy(info->ProductName, DeviceInfo::MaxNameLength,
+ is7Inch ? "Oculus Rift DK1" :
+ ((HResolution >= 1920) ? "Oculus Rift DK HD" : "Oculus Rift DK1-Prototype") );
+ OVR_strcpy(info->Manufacturer, DeviceInfo::MaxNameLength, "Oculus VR");
+ info->Type = Device_HMD;
+ info->Version = 0;
+
+ // Display detection.
+ if (info->InfoClassType == Device_HMD)
+ {
+ HMDInfo* hmdInfo = static_cast<HMDInfo*>(info);
+
+ hmdInfo->DesktopX = DesktopX;
+ hmdInfo->DesktopY = DesktopY;
+ hmdInfo->HResolution = HResolution;
+ hmdInfo->VResolution = VResolution;
+ hmdInfo->HScreenSize = HScreenSize;
+ hmdInfo->VScreenSize = VScreenSize;
+ hmdInfo->VScreenCenter = VScreenSize * 0.5f;
+ hmdInfo->InterpupillaryDistance = 0.064f; // Default IPD; should be configurable.
+ hmdInfo->LensSeparationDistance = 0.0635f;
+
+ // Obtain IPD from profile.
+ Ptr<Profile> profile = *GetProfileAddRef();
+
+ if (profile)
+ {
+ hmdInfo->InterpupillaryDistance = profile->GetIPD();
+ // TBD: Switch on EyeCup type.
+ }
+
+ if (Contents & Contents_Distortion)
+ {
+ memcpy(hmdInfo->DistortionK, DistortionK, sizeof(float)*4);
+ }
+ else
+ {
+ if (is7Inch)
+ {
+ // 7" screen.
+ hmdInfo->DistortionK[0] = 1.0f;
+ hmdInfo->DistortionK[1] = 0.22f;
+ hmdInfo->DistortionK[2] = 0.24f;
+ hmdInfo->EyeToScreenDistance = 0.041f;
+ }
+ else
+ {
+ hmdInfo->DistortionK[0] = 1.0f;
+ hmdInfo->DistortionK[1] = 0.18f;
+ hmdInfo->DistortionK[2] = 0.115f;
+
+ if (HResolution == 1920)
+ hmdInfo->EyeToScreenDistance = 0.040f;
+ else
+ hmdInfo->EyeToScreenDistance = 0.0387f;
+ }
+
+ hmdInfo->ChromaAbCorrection[0] = 0.996f;
+ hmdInfo->ChromaAbCorrection[1] = -0.004f;
+ hmdInfo->ChromaAbCorrection[2] = 1.014f;
+ hmdInfo->ChromaAbCorrection[3] = 0.0f;
+ }
+
+ OVR_strcpy(hmdInfo->DisplayDeviceName, sizeof(hmdInfo->DisplayDeviceName),
+ DisplayDeviceName.ToCStr());
+ }
+
+ return true;
+}
+
+//-------------------------------------------------------------------------------------
+// ***** HMDDevice
+
+HMDDevice::HMDDevice(HMDDeviceCreateDesc* createDesc)
+ : OVR::DeviceImpl<OVR::HMDDevice>(createDesc, 0)
+{
+}
+HMDDevice::~HMDDevice()
+{
+}
+
+bool HMDDevice::Initialize(DeviceBase* parent)
+{
+ pParent = parent;
+
+ // Initialize user profile to default for device.
+ ProfileManager* profileManager = GetManager()->GetProfileManager();
+ ProfileName = profileManager->GetDefaultProfileName(getDesc()->GetProfileType());
+
+ return true;
+}
+void HMDDevice::Shutdown()
+{
+ ProfileName.Clear();
+ pCachedProfile.Clear();
+ pParent.Clear();
+}
+
+Profile* HMDDevice::GetProfile() const
+{
+ if (!pCachedProfile)
+ pCachedProfile = *getDesc()->GetProfileAddRef();
+ return pCachedProfile.GetPtr();
+}
+
+const char* HMDDevice::GetProfileName() const
+{
+ return ProfileName.ToCStr();
+}
+
+bool HMDDevice::SetProfileName(const char* name)
+{
+ pCachedProfile.Clear();
+ if (!name)
+ {
+ ProfileName.Clear();
+ return 0;
+ }
+ if (GetManager()->GetProfileManager()->HasProfile(getDesc()->GetProfileType(), name))
+ {
+ ProfileName = name;
+ return true;
+ }
+ return false;
+}
+
+OVR::SensorDevice* HMDDevice::GetSensor()
+{
+ // Just return first sensor found since we have no way to match it yet.
+ OVR::SensorDevice* sensor = GetManager()->EnumerateDevices<SensorDevice>().CreateDevice();
+ if (sensor)
+ sensor->SetCoordinateFrame(SensorDevice::Coord_HMD);
+ return sensor;
+}
+
+}} // namespace OVR::Win32
+
+
diff --git a/LibOVR/Src/OVR_Win32_HMDDevice.h b/LibOVR/Src/OVR_Win32_HMDDevice.h
index f653de9..e4b6657 100644
--- a/LibOVR/Src/OVR_Win32_HMDDevice.h
+++ b/LibOVR/Src/OVR_Win32_HMDDevice.h
@@ -1,133 +1,157 @@
-/************************************************************************************
-
-Filename : OVR_Win32_HMDDevice.h
-Content : Win32 HMDDevice implementation
-Created : September 21, 2012
-Authors : Michael Antonov
-
-Copyright : Copyright 2012 Oculus VR, Inc. All Rights reserved.
-
-Use of this software is subject to the terms of the Oculus license
-agreement provided at the time of installation or download, or which
-otherwise accompanies this software in either electronic or hard copy form.
-
-*************************************************************************************/
-
-#ifndef OVR_Win32_HMDDevice_h
-#define OVR_Win32_HMDDevice_h
-
-#include "OVR_Win32_DeviceManager.h"
-
-namespace OVR { namespace Win32 {
-
-class HMDDevice;
-
-
-//-------------------------------------------------------------------------------------
-
-// HMDDeviceFactory enumerates attached Oculus HMD devices.
-//
-// This is currently done by matching monitor device strings.
-
-class HMDDeviceFactory : public DeviceFactory
-{
-public:
- static HMDDeviceFactory Instance;
-
- // Enumerates devices, creating and destroying relevant objects in manager.
- virtual void EnumerateDevices(EnumerateVisitor& visitor);
-
-protected:
- DeviceManager* getManager() const { return (DeviceManager*) pManager; }
-};
-
-
-class HMDDeviceCreateDesc : public DeviceCreateDesc
-{
- friend class HMDDevice;
-
-protected:
- enum
- {
- Contents_Screen = 1,
- Contents_Distortion = 2,
- Contents_7Inch = 4,
- };
- String DeviceId;
- String DisplayDeviceName;
- int DesktopX, DesktopY;
- unsigned Contents;
- unsigned HResolution, VResolution;
- float HScreenSize, VScreenSize;
- float DistortionK[4];
-
-public:
- HMDDeviceCreateDesc(DeviceFactory* factory,
- const String& deviceId, const String& displayDeviceName);
- HMDDeviceCreateDesc(const HMDDeviceCreateDesc& other);
-
- virtual DeviceCreateDesc* Clone() const
- {
- return new HMDDeviceCreateDesc(*this);
- }
-
- virtual DeviceBase* NewDeviceInstance();
-
- virtual MatchResult MatchDevice(const DeviceCreateDesc& other,
- DeviceCreateDesc**) const;
-
- // Matches device by path.
- virtual bool MatchDevice(const String& path);
-
- virtual bool UpdateMatchedCandidate(const DeviceCreateDesc&, bool* newDeviceFlag = NULL);
-
- virtual bool GetDeviceInfo(DeviceInfo* info) const;
-
- void SetScreenParameters(int x, int y, unsigned hres, unsigned vres, float hsize, float vsize)
- {
- DesktopX = x;
- DesktopY = y;
- HResolution = hres;
- VResolution = vres;
- HScreenSize = hsize;
- VScreenSize = vsize;
- Contents |= Contents_Screen;
- }
- void SetDistortion(const float* dks)
- {
- for (int i = 0; i < 4; i++)
- DistortionK[i] = dks[i];
- Contents |= Contents_Distortion;
- }
-
- void Set7Inch() { Contents |= Contents_7Inch; }
-
- bool Is7Inch() const;
-};
-
-
-//-------------------------------------------------------------------------------------
-
-// HMDDevice represents an Oculus HMD device unit. An instance of this class
-// is typically created from the DeviceManager.
-// After HMD device is created, we its sensor data can be obtained by
-// first creating a Sensor object and then wrappig it in SensorFusion.
-
-class HMDDevice : public DeviceImpl<OVR::HMDDevice>
-{
-public:
- HMDDevice(HMDDeviceCreateDesc* createDesc);
- ~HMDDevice();
-
- virtual bool Initialize(DeviceBase* parent);
- virtual void Shutdown();
-
- // Query associated sensor.
- virtual OVR::SensorDevice* GetSensor();
-};
-
-
-}} // namespace OVR::Win32
-
-#endif // OVR_Win32_HMDDevice_h
-
+/************************************************************************************
+
+Filename : OVR_Win32_HMDDevice.h
+Content : Win32 HMDDevice implementation
+Created : September 21, 2012
+Authors : Michael Antonov
+
+Copyright : Copyright 2012 Oculus VR, Inc. All Rights reserved.
+
+Use of this software is subject to the terms of the Oculus license
+agreement provided at the time of installation or download, or which
+otherwise accompanies this software in either electronic or hard copy form.
+
+*************************************************************************************/
+
+#ifndef OVR_Win32_HMDDevice_h
+#define OVR_Win32_HMDDevice_h
+
+#include "OVR_Win32_DeviceManager.h"
+#include "OVR_Profile.h"
+
+namespace OVR { namespace Win32 {
+
+class HMDDevice;
+
+
+//-------------------------------------------------------------------------------------
+
+// HMDDeviceFactory enumerates attached Oculus HMD devices.
+//
+// This is currently done by matching monitor device strings.
+
+class HMDDeviceFactory : public DeviceFactory
+{
+public:
+ static HMDDeviceFactory Instance;
+
+ // Enumerates devices, creating and destroying relevant objects in manager.
+ virtual void EnumerateDevices(EnumerateVisitor& visitor);
+
+protected:
+ DeviceManager* getManager() const { return (DeviceManager*) pManager; }
+};
+
+
+class HMDDeviceCreateDesc : public DeviceCreateDesc
+{
+ friend class HMDDevice;
+
+protected:
+ enum
+ {
+ Contents_Screen = 1,
+ Contents_Distortion = 2,
+ Contents_7Inch = 4,
+ };
+ String DeviceId;
+ String DisplayDeviceName;
+ int DesktopX, DesktopY;
+ unsigned Contents;
+ unsigned HResolution, VResolution;
+ float HScreenSize, VScreenSize;
+ float DistortionK[4];
+
+public:
+ HMDDeviceCreateDesc(DeviceFactory* factory,
+ const String& deviceId, const String& displayDeviceName);
+ HMDDeviceCreateDesc(const HMDDeviceCreateDesc& other);
+
+ virtual DeviceCreateDesc* Clone() const
+ {
+ return new HMDDeviceCreateDesc(*this);
+ }
+
+ virtual DeviceBase* NewDeviceInstance();
+
+ virtual MatchResult MatchDevice(const DeviceCreateDesc& other,
+ DeviceCreateDesc**) const;
+
+ // Matches device by path.
+ virtual bool MatchDevice(const String& path);
+
+ virtual bool UpdateMatchedCandidate(const DeviceCreateDesc&, bool* newDeviceFlag = NULL);
+
+ virtual bool GetDeviceInfo(DeviceInfo* info) const;
+
+ // Requests the currently used default profile. This profile affects the
+ // settings reported by HMDInfo.
+ Profile* GetProfileAddRef() const;
+
+ ProfileType GetProfileType() const
+ {
+ return (HResolution >= 1920) ? Profile_RiftDKHD : Profile_RiftDK1;
+ }
+
+
+ void SetScreenParameters(int x, int y, unsigned hres, unsigned vres, float hsize, float vsize)
+ {
+ DesktopX = x;
+ DesktopY = y;
+ HResolution = hres;
+ VResolution = vres;
+ HScreenSize = hsize;
+ VScreenSize = vsize;
+ Contents |= Contents_Screen;
+ }
+ void SetDistortion(const float* dks)
+ {
+ for (int i = 0; i < 4; i++)
+ DistortionK[i] = dks[i];
+ Contents |= Contents_Distortion;
+ }
+
+ void Set7Inch() { Contents |= Contents_7Inch; }
+
+ bool Is7Inch() const;
+};
+
+
+//-------------------------------------------------------------------------------------
+
+// HMDDevice represents an Oculus HMD device unit. An instance of this class
+// is typically created from the DeviceManager.
+// After HMD device is created, we its sensor data can be obtained by
+// first creating a Sensor object and then wrappig it in SensorFusion.
+
+class HMDDevice : public DeviceImpl<OVR::HMDDevice>
+{
+public:
+ HMDDevice(HMDDeviceCreateDesc* createDesc);
+ ~HMDDevice();
+
+ virtual bool Initialize(DeviceBase* parent);
+ virtual void Shutdown();
+
+ // Requests the currently used default profile. This profile affects the
+ // settings reported by HMDInfo.
+ virtual Profile* GetProfile() const;
+ virtual const char* GetProfileName() const;
+ virtual bool SetProfileName(const char* name);
+
+ // Query associated sensor.
+ virtual OVR::SensorDevice* GetSensor();
+
+protected:
+ HMDDeviceCreateDesc* getDesc() const { return (HMDDeviceCreateDesc*)pCreateDesc.GetPtr(); }
+
+ // User name for the profile used with this device.
+ String ProfileName;
+ mutable Ptr<Profile> pCachedProfile;
+};
+
+
+}} // namespace OVR::Win32
+
+#endif // OVR_Win32_HMDDevice_h
+
diff --git a/LibOVR/Src/OVR_Win32_SensorDevice.cpp b/LibOVR/Src/OVR_Win32_SensorDevice.cpp
index ce02b9e..c69e618 100644
--- a/LibOVR/Src/OVR_Win32_SensorDevice.cpp
+++ b/LibOVR/Src/OVR_Win32_SensorDevice.cpp
@@ -1,47 +1,47 @@
-/************************************************************************************
-
-Filename : OVR_Win32_SensorDevice.cpp
-Content : Win32 SensorDevice implementation
-Created : March 12, 2013
-Authors : Lee Cooper
-
-Copyright : Copyright 2013 Oculus VR, Inc. All Rights reserved.
-
-Use of this software is subject to the terms of the Oculus license
-agreement provided at the time of installation or download, or which
-otherwise accompanies this software in either electronic or hard copy form.
-
-*************************************************************************************/
-
-#include "OVR_Win32_SensorDevice.h"
-
-#include "OVR_Win32_HMDDevice.h"
-#include "OVR_SensorImpl.h"
-#include "OVR_DeviceImpl.h"
-
-namespace OVR { namespace Win32 {
-
-} // namespace Win32
-
-//-------------------------------------------------------------------------------------
-void SensorDeviceImpl::EnumerateHMDFromSensorDisplayInfo
- (const SensorDisplayInfoImpl& displayInfo,
- DeviceFactory::EnumerateVisitor& visitor)
-{
-
- Win32::HMDDeviceCreateDesc hmdCreateDesc(&Win32::HMDDeviceFactory::Instance, String(), String());
- hmdCreateDesc.SetScreenParameters( 0, 0,
- displayInfo.HResolution, displayInfo.VResolution,
- displayInfo.HScreenSize, displayInfo.VScreenSize);
-
- if ((displayInfo.DistortionType & SensorDisplayInfoImpl::Mask_BaseFmt) == SensorDisplayInfoImpl::Base_Distortion)
- hmdCreateDesc.SetDistortion(displayInfo.DistortionK);
- if (displayInfo.HScreenSize > 0.14f)
- hmdCreateDesc.Set7Inch();
-
- visitor.Visit(hmdCreateDesc);
-}
-
-} // namespace OVR
-
-
+/************************************************************************************
+
+Filename : OVR_Win32_SensorDevice.cpp
+Content : Win32 SensorDevice implementation
+Created : March 12, 2013
+Authors : Lee Cooper
+
+Copyright : Copyright 2013 Oculus VR, Inc. All Rights reserved.
+
+Use of this software is subject to the terms of the Oculus license
+agreement provided at the time of installation or download, or which
+otherwise accompanies this software in either electronic or hard copy form.
+
+*************************************************************************************/
+
+#include "OVR_Win32_SensorDevice.h"
+
+#include "OVR_Win32_HMDDevice.h"
+#include "OVR_SensorImpl.h"
+#include "OVR_DeviceImpl.h"
+
+namespace OVR { namespace Win32 {
+
+} // namespace Win32
+
+//-------------------------------------------------------------------------------------
+void SensorDeviceImpl::EnumerateHMDFromSensorDisplayInfo
+ (const SensorDisplayInfoImpl& displayInfo,
+ DeviceFactory::EnumerateVisitor& visitor)
+{
+
+ Win32::HMDDeviceCreateDesc hmdCreateDesc(&Win32::HMDDeviceFactory::Instance, String(), String());
+ hmdCreateDesc.SetScreenParameters( 0, 0,
+ displayInfo.HResolution, displayInfo.VResolution,
+ displayInfo.HScreenSize, displayInfo.VScreenSize);
+
+ if ((displayInfo.DistortionType & SensorDisplayInfoImpl::Mask_BaseFmt) == SensorDisplayInfoImpl::Base_Distortion)
+ hmdCreateDesc.SetDistortion(displayInfo.DistortionK);
+ if (displayInfo.HScreenSize > 0.14f)
+ hmdCreateDesc.Set7Inch();
+
+ visitor.Visit(hmdCreateDesc);
+}
+
+} // namespace OVR
+
+
diff --git a/LibOVR/Src/OVR_Win32_SensorDevice.h b/LibOVR/Src/OVR_Win32_SensorDevice.h
index 730620e..624d3b5 100644
--- a/LibOVR/Src/OVR_Win32_SensorDevice.h
+++ b/LibOVR/Src/OVR_Win32_SensorDevice.h
@@ -1,24 +1,24 @@
-/************************************************************************************
-
-Filename : OVR_Win32_SensorDevice.h
-Content : Win32 SensorDevice implementation
-Created : March 12, 2013
-Authors : Lee Cooper
-
-Copyright : Copyright 2013 Oculus VR, Inc. All Rights reserved.
-
-Use of this software is subject to the terms of the Oculus license
-agreement provided at the time of installation or download, or which
-otherwise accompanies this software in either electronic or hard copy form.
-
-*************************************************************************************/
-
-#ifndef OVR_Win32_SensorDevice_h
-#define OVR_Win32_SensorDevice_h
-
-namespace OVR { namespace Win32 {
-
-}} // namespace OVR::Win32
-
-#endif // OVR_Win32_SensorDevice_h
-
+/************************************************************************************
+
+Filename : OVR_Win32_SensorDevice.h
+Content : Win32 SensorDevice implementation
+Created : March 12, 2013
+Authors : Lee Cooper
+
+Copyright : Copyright 2013 Oculus VR, Inc. All Rights reserved.
+
+Use of this software is subject to the terms of the Oculus license
+agreement provided at the time of installation or download, or which
+otherwise accompanies this software in either electronic or hard copy form.
+
+*************************************************************************************/
+
+#ifndef OVR_Win32_SensorDevice_h
+#define OVR_Win32_SensorDevice_h
+
+namespace OVR { namespace Win32 {
+
+}} // namespace OVR::Win32
+
+#endif // OVR_Win32_SensorDevice_h
+
diff --git a/LibOVR/Src/Util/Util_LatencyTest.cpp b/LibOVR/Src/Util/Util_LatencyTest.cpp
index 1a1c303..57c2769 100644
--- a/LibOVR/Src/Util/Util_LatencyTest.cpp
+++ b/LibOVR/Src/Util/Util_LatencyTest.cpp
@@ -1,560 +1,571 @@
-/************************************************************************************
-
-Filename : Util_LatencyTest.cpp
-Content : Wraps the lower level LatencyTester interface and adds functionality.
-Created : February 14, 2013
-Authors : Lee Cooper
-
-Copyright : Copyright 2013 Oculus VR, Inc. All Rights reserved.
-
-Use of this software is subject to the terms of the Oculus license
-agreement provided at the time of installation or download, or which
-otherwise accompanies this software in either electronic or hard copy form.
-
-*************************************************************************************/
-
-#include "Util_LatencyTest.h"
-
-#include "../Kernel/OVR_Log.h"
-#include "../Kernel/OVR_Timer.h"
-
-namespace OVR { namespace Util {
-
-static const UInt32 TIME_TO_WAIT_FOR_SETTLE_PRE_CALIBRATION = 16*10;
-static const UInt32 TIME_TO_WAIT_FOR_SETTLE_POST_CALIBRATION = 16*10;
-static const UInt32 TIME_TO_WAIT_FOR_SETTLE_POST_MEASUREMENT = 16*5;
-static const UInt32 TIME_TO_WAIT_FOR_SETTLE_POST_MEASUREMENT_RANDOMNESS = 16*5;
-static const UInt32 DEFAULT_NUMBER_OF_SAMPLES = 10; // For both color 1->2 and color 2->1 transitions.
-static const UInt32 INITIAL_SAMPLES_TO_IGNORE = 4;
-static const UInt32 TIMEOUT_WAITING_FOR_TEST_STARTED = 1000;
-static const UInt32 TIMEOUT_WAITING_FOR_COLOR_DETECTED = 4000;
-static const Color CALIBRATE_BLACK(0, 0, 0);
-static const Color CALIBRATE_WHITE(255, 255, 255);
-static const Color COLOR1(0, 0, 0);
-static const Color COLOR2(255, 255, 255);
-static const Color SENSOR_DETECT_THRESHOLD(128, 255, 255);
-static const float BIG_FLOAT = 1000000.0f;
-static const float SMALL_FLOAT = -1000000.0f;
-
-//-------------------------------------------------------------------------------------
-// ***** LatencyTest
-
-LatencyTest::LatencyTest(LatencyTestDevice* device)
- : Handler(getThis())
-{
- if (device != NULL)
- {
- SetDevice(device);
- }
-
- reset();
-
- srand(Timer::GetTicksMs());
-}
-
-LatencyTest::~LatencyTest()
-{
- clearMeasurementResults();
-}
-
-bool LatencyTest::SetDevice(LatencyTestDevice* device)
-{
-
- if (device != Device)
- {
- if (device != NULL)
- {
- if (device->GetMessageHandler() != NULL)
- {
- OVR_DEBUG_LOG(
- ("LatencyTest::AttachToDevice failed - device %p already has handler", device));
- return false;
- }
- }
-
- if (Device != NULL)
- {
- Device->SetMessageHandler(0);
- }
- Device = device;
-
- if (Device != NULL)
- {
- Device->SetMessageHandler(&Handler);
-
- // Set trigger threshold.
- LatencyTestConfiguration configuration(SENSOR_DETECT_THRESHOLD, false); // No samples streaming.
- Device->SetConfiguration(configuration, true);
- }
- }
-
- return true;
-}
-
-UInt32 LatencyTest::getRandomComponent(UInt32 range)
-{
- UInt32 val = rand() % range;
- return val;
-}
-
-void LatencyTest::BeginTest()
-{
- if (State == State_WaitingForButton)
- {
- // Set color to black and wait a while.
- RenderColor = CALIBRATE_BLACK;
-
- State = State_WaitingForSettlePreCalibrationColorBlack;
- OVR_DEBUG_LOG(("State_WaitingForButton -> State_WaitingForSettlePreCalibrationColorBlack."));
-
- setTimer(TIME_TO_WAIT_FOR_SETTLE_PRE_CALIBRATION);
- }
-}
-
-void LatencyTest::handleMessage(const Message& msg, LatencyTestMessageType latencyTestMessage)
-{
- // For debugging.
-/* if (msg.Type == Message_LatencyTestSamples)
- {
- MessageLatencyTestSamples* pSamples = (MessageLatencyTestSamples*) &msg;
-
- if (pSamples->Samples.GetSize() > 0)
- {
- // Just show the first one for now.
- Color c = pSamples->Samples[0];
- OVR_DEBUG_LOG(("%d %d %d", c.R, c.G, c.B));
- }
- return;
- }
-*/
-
- if (latencyTestMessage == LatencyTest_Timer)
- {
- if (!Device)
- {
- reset();
- return;
- }
-
- if (State == State_WaitingForSettlePreCalibrationColorBlack)
- {
- // Send calibrate message to device and wait a while.
- LatencyTestCalibrate calibrate(CALIBRATE_BLACK);
- Device->SetCalibrate(calibrate);
-
- State = State_WaitingForSettlePostCalibrationColorBlack;
- OVR_DEBUG_LOG(("State_WaitingForSettlePreCalibrationColorBlack -> State_WaitingForSettlePostCalibrationColorBlack."));
-
- setTimer(TIME_TO_WAIT_FOR_SETTLE_POST_CALIBRATION);
- }
- else if (State == State_WaitingForSettlePostCalibrationColorBlack)
- {
- // Change color to white and wait a while.
- RenderColor = CALIBRATE_WHITE;
-
- State = State_WaitingForSettlePreCalibrationColorWhite;
- OVR_DEBUG_LOG(("State_WaitingForSettlePostCalibrationColorBlack -> State_WaitingForSettlePreCalibrationColorWhite."));
-
- setTimer(TIME_TO_WAIT_FOR_SETTLE_PRE_CALIBRATION);
- }
- else if (State == State_WaitingForSettlePreCalibrationColorWhite)
- {
- // Send calibrate message to device and wait a while.
- LatencyTestCalibrate calibrate(CALIBRATE_WHITE);
- Device->SetCalibrate(calibrate);
-
- State = State_WaitingForSettlePostCalibrationColorWhite;
- OVR_DEBUG_LOG(("State_WaitingForSettlePreCalibrationColorWhite -> State_WaitingForSettlePostCalibrationColorWhite."));
-
- setTimer(TIME_TO_WAIT_FOR_SETTLE_POST_CALIBRATION);
- }
- else if (State == State_WaitingForSettlePostCalibrationColorWhite)
- {
- // Calibration is done. Switch to color 1 and wait for it to settle.
- RenderColor = COLOR1;
-
- State = State_WaitingForSettlePostMeasurement;
- OVR_DEBUG_LOG(("State_WaitingForSettlePostCalibrationColorWhite -> State_WaitingForSettlePostMeasurement."));
-
- UInt32 waitTime = TIME_TO_WAIT_FOR_SETTLE_POST_MEASUREMENT + getRandomComponent(TIME_TO_WAIT_FOR_SETTLE_POST_MEASUREMENT_RANDOMNESS);
- setTimer(waitTime);
- }
- else if (State == State_WaitingForSettlePostMeasurement)
- {
- // Prepare for next measurement.
-
- // Create a new result object.
- MeasurementResult* pResult = new MeasurementResult();
- Results.PushBack(pResult);
-
- State = State_WaitingToTakeMeasurement;
- OVR_DEBUG_LOG(("State_WaitingForSettlePostMeasurement -> State_WaitingToTakeMeasurement."));
- }
- else if (State == State_WaitingForTestStarted)
- {
- // We timed out waiting for 'TestStarted'. Abandon this measurement and setup for the next.
- getActiveResult()->TimedOutWaitingForTestStarted = true;
-
- State = State_WaitingForSettlePostMeasurement;
- OVR_DEBUG_LOG(("** Timed out waiting for 'TestStarted'."));
- OVR_DEBUG_LOG(("State_WaitingForTestStarted -> State_WaitingForSettlePostMeasurement."));
-
- UInt32 waitTime = TIME_TO_WAIT_FOR_SETTLE_POST_MEASUREMENT + getRandomComponent(TIME_TO_WAIT_FOR_SETTLE_POST_MEASUREMENT_RANDOMNESS);
- setTimer(waitTime);
- }
- else if (State == State_WaitingForColorDetected)
- {
- // We timed out waiting for 'ColorDetected'. Abandon this measurement and setup for the next.
- getActiveResult()->TimedOutWaitingForColorDetected = true;
-
- State = State_WaitingForSettlePostMeasurement;
- OVR_DEBUG_LOG(("** Timed out waiting for 'ColorDetected'."));
- OVR_DEBUG_LOG(("State_WaitingForColorDetected -> State_WaitingForSettlePostMeasurement."));
-
- UInt32 waitTime = TIME_TO_WAIT_FOR_SETTLE_POST_MEASUREMENT + getRandomComponent(TIME_TO_WAIT_FOR_SETTLE_POST_MEASUREMENT_RANDOMNESS);
- setTimer(waitTime);
- }
- }
- else if (latencyTestMessage == LatencyTest_ProcessInputs)
- {
- if (State == State_WaitingToTakeMeasurement)
- {
- if (!Device)
- {
- reset();
- return;
- }
-
- // Send 'StartTest' feature report with opposite target color.
- if (RenderColor == COLOR1)
- {
- RenderColor = COLOR2;
- }
- else
- {
- RenderColor = COLOR1;
- }
-
- getActiveResult()->TargetColor = RenderColor;
-
- // Record time so we can determine usb roundtrip time.
- getActiveResult()->StartTestTicksMicroS = Timer::GetTicks();
-
- LatencyTestStartTest startTest(RenderColor);
- Device->SetStartTest(startTest);
-
- State = State_WaitingForTestStarted;
- OVR_DEBUG_LOG(("State_WaitingToTakeMeasurement -> State_WaitingForTestStarted."));
-
- setTimer(TIMEOUT_WAITING_FOR_TEST_STARTED);
- }
- }
- else if (msg.Type == Message_LatencyTestButton)
- {
- BeginTest();
- }
- else if (msg.Type == Message_LatencyTestStarted)
- {
- if (State == State_WaitingForTestStarted)
- {
- clearTimer();
-
- // Record time so we can determine usb roundtrip time.
- getActiveResult()->TestStartedTicksMicroS = Timer::GetTicks();
-
- State = State_WaitingForColorDetected;
- OVR_DEBUG_LOG(("State_WaitingForTestStarted -> State_WaitingForColorDetected."));
-
- setTimer(TIMEOUT_WAITING_FOR_COLOR_DETECTED);
- }
- }
- else if (msg.Type == Message_LatencyTestColorDetected)
- {
- if (State == State_WaitingForColorDetected)
- {
- // Record time to detect color.
- MessageLatencyTestColorDetected* pDetected = (MessageLatencyTestColorDetected*) &msg;
- UInt16 elapsedTime = pDetected->Elapsed;
- OVR_DEBUG_LOG(("Time to 'ColorDetected' = %d", elapsedTime));
-
- getActiveResult()->DeviceMeasuredElapsedMilliS = elapsedTime;
-
- if (areResultsComplete())
- {
- // We're done.
- processResults();
- reset();
- }
- else
- {
- // Run another measurement.
- State = State_WaitingForSettlePostMeasurement;
- OVR_DEBUG_LOG(("State_WaitingForColorDetected -> State_WaitingForSettlePostMeasurement."));
-
- UInt32 waitTime = TIME_TO_WAIT_FOR_SETTLE_POST_MEASUREMENT + getRandomComponent(TIME_TO_WAIT_FOR_SETTLE_POST_MEASUREMENT_RANDOMNESS);
- setTimer(waitTime);
- }
- }
- }
- else if (msg.Type == Message_DeviceRemoved)
- {
- reset();
- }
-}
-
-LatencyTest::MeasurementResult* LatencyTest::getActiveResult()
-{
- OVR_ASSERT(!Results.IsEmpty());
- return Results.GetLast();
-}
-
-void LatencyTest::setTimer(UInt32 timeMilliS)
-{
- ActiveTimerMilliS = timeMilliS;
-}
-
-void LatencyTest::clearTimer()
-{
- ActiveTimerMilliS = 0;
-}
-
-void LatencyTest::reset()
-{
- clearMeasurementResults();
- State = State_WaitingForButton;
-
- HaveOldTime = false;
- ActiveTimerMilliS = 0;
-}
-
-void LatencyTest::clearMeasurementResults()
-{
- while(!Results.IsEmpty())
- {
- MeasurementResult* pElem = Results.GetFirst();
- pElem->RemoveNode();
- delete pElem;
- }
-}
-
-LatencyTest::LatencyTestHandler::~LatencyTestHandler()
-{
- RemoveHandlerFromDevices();
-}
-
-void LatencyTest::LatencyTestHandler::OnMessage(const Message& msg)
-{
- pLatencyTestUtil->handleMessage(msg);
-}
-
-void LatencyTest::ProcessInputs()
-{
- updateForTimeouts();
- handleMessage(Message(), LatencyTest_ProcessInputs);
-}
-
-bool LatencyTest::DisplayScreenColor(Color& colorToDisplay)
-{
- updateForTimeouts();
-
- if (State == State_WaitingForButton)
- {
- return false;
- }
-
- colorToDisplay = RenderColor;
- return true;
-}
-
-const char* LatencyTest::GetResultsString()
-{
- if (!ResultsString.IsEmpty() && ReturnedResultString != ResultsString.ToCStr())
- {
- ReturnedResultString = ResultsString;
- return ReturnedResultString.ToCStr();
- }
-
- return NULL;
-}
-
-bool LatencyTest::areResultsComplete()
-{
- UInt32 initialMeasurements = 0;
-
- UInt32 measurements1to2 = 0;
- UInt32 measurements2to1 = 0;
-
- MeasurementResult* pCurr = Results.GetFirst();
- while(true)
- {
- // Process.
- if (!pCurr->TimedOutWaitingForTestStarted &&
- !pCurr->TimedOutWaitingForColorDetected)
- {
- initialMeasurements++;
-
- if (initialMeasurements > INITIAL_SAMPLES_TO_IGNORE)
- {
- if (pCurr->TargetColor == COLOR2)
- {
- measurements1to2++;
- }
- else
- {
- measurements2to1++;
- }
- }
- }
-
- if (Results.IsLast(pCurr))
- {
- break;
- }
- pCurr = Results.GetNext(pCurr);
- }
-
- if (measurements1to2 >= DEFAULT_NUMBER_OF_SAMPLES &&
- measurements2to1 >= DEFAULT_NUMBER_OF_SAMPLES)
- {
- return true;
- }
-
- return false;
-}
-
-void LatencyTest::processResults()
-{
-
- UInt32 minTime1To2 = UINT_MAX;
- UInt32 maxTime1To2 = 0;
- float averageTime1To2 = 0.0f;
- UInt32 minTime2To1 = UINT_MAX;
- UInt32 maxTime2To1 = 0;
- float averageTime2To1 = 0.0f;
-
- float minUSBTripMilliS = BIG_FLOAT;
- float maxUSBTripMilliS = SMALL_FLOAT;
- float averageUSBTripMilliS = 0.0f;
- UInt32 countUSBTripTime = 0;
-
- UInt32 measurementsCount = 0;
- UInt32 measurements1to2 = 0;
- UInt32 measurements2to1 = 0;
-
- MeasurementResult* pCurr = Results.GetFirst();
- UInt32 count = 0;
- while(true)
- {
- count++;
-
- if (!pCurr->TimedOutWaitingForTestStarted &&
- !pCurr->TimedOutWaitingForColorDetected)
- {
- measurementsCount++;
-
- if (measurementsCount > INITIAL_SAMPLES_TO_IGNORE)
- {
- if (pCurr->TargetColor == COLOR2)
- {
- measurements1to2++;
-
- if (measurements1to2 <= DEFAULT_NUMBER_OF_SAMPLES)
- {
- UInt32 elapsed = pCurr->DeviceMeasuredElapsedMilliS;
-
- minTime1To2 = Alg::Min(elapsed, minTime1To2);
- maxTime1To2 = Alg::Max(elapsed, maxTime1To2);
-
- averageTime1To2 += (float) elapsed;
- }
- }
- else
- {
- measurements2to1++;
-
- if (measurements2to1 <= DEFAULT_NUMBER_OF_SAMPLES)
- {
- UInt32 elapsed = pCurr->DeviceMeasuredElapsedMilliS;
-
- minTime2To1 = Alg::Min(elapsed, minTime2To1);
- maxTime2To1 = Alg::Max(elapsed, maxTime2To1);
-
- averageTime2To1 += (float) elapsed;
- }
- }
-
- float usbRountripElapsedMilliS = 0.001f * (float) (pCurr->TestStartedTicksMicroS - pCurr->StartTestTicksMicroS);
- minUSBTripMilliS = Alg::Min(usbRountripElapsedMilliS, minUSBTripMilliS);
- maxUSBTripMilliS = Alg::Max(usbRountripElapsedMilliS, maxUSBTripMilliS);
- averageUSBTripMilliS += usbRountripElapsedMilliS;
- countUSBTripTime++;
- }
- }
-
- if (measurements1to2 >= DEFAULT_NUMBER_OF_SAMPLES &&
- measurements2to1 >= DEFAULT_NUMBER_OF_SAMPLES)
- {
- break;
- }
-
- if (Results.IsLast(pCurr))
- {
- break;
- }
- pCurr = Results.GetNext(pCurr);
- }
-
- averageTime1To2 /= (float) DEFAULT_NUMBER_OF_SAMPLES;
- averageTime2To1 /= (float) DEFAULT_NUMBER_OF_SAMPLES;
-
- averageUSBTripMilliS /= countUSBTripTime;
-
- float finalResult = 0.5f * (averageTime1To2 + averageTime2To1);
- finalResult += averageUSBTripMilliS;
-
- ResultsString.Clear();
- ResultsString.AppendFormat("RESULT=%.1f (add half Tracker period) [b->w %d|%.1f|%d] [w->b %d|%.1f|%d] [usb rndtrp %.1f|%.1f|%.1f] [cnt %d] [tmouts %d]",
- finalResult,
- minTime1To2, averageTime1To2, maxTime1To2,
- minTime2To1, averageTime2To1, maxTime2To1,
- minUSBTripMilliS, averageUSBTripMilliS, maxUSBTripMilliS,
- DEFAULT_NUMBER_OF_SAMPLES*2, count - measurementsCount);
-}
-
-void LatencyTest::updateForTimeouts()
-{
- if (!HaveOldTime)
- {
- HaveOldTime = true;
- OldTime = Timer::GetTicksMs();
- return;
- }
-
- UInt32 newTime = Timer::GetTicksMs();
- UInt32 elapsedMilliS = newTime - OldTime;
- if (newTime < OldTime)
- {
- elapsedMilliS = OldTime - newTime;
- elapsedMilliS = UINT_MAX - elapsedMilliS;
- }
- OldTime = newTime;
-
- elapsedMilliS = Alg::Min(elapsedMilliS, (UInt32) 100); // Clamp at 100mS in case we're not being called very often.
-
-
- if (ActiveTimerMilliS == 0)
- {
- return;
- }
-
- if (elapsedMilliS >= ActiveTimerMilliS)
- {
- ActiveTimerMilliS = 0;
- handleMessage(Message(), LatencyTest_Timer);
- return;
- }
-
- ActiveTimerMilliS -= elapsedMilliS;
-}
-
-}} // namespace OVR::Util
+/************************************************************************************
+
+Filename : Util_LatencyTest.cpp
+Content : Wraps the lower level LatencyTester interface and adds functionality.
+Created : February 14, 2013
+Authors : Lee Cooper
+
+Copyright : Copyright 2013 Oculus VR, Inc. All Rights reserved.
+
+Use of this software is subject to the terms of the Oculus license
+agreement provided at the time of installation or download, or which
+otherwise accompanies this software in either electronic or hard copy form.
+
+*************************************************************************************/
+
+#include "Util_LatencyTest.h"
+
+#include "../Kernel/OVR_Log.h"
+#include "../Kernel/OVR_Timer.h"
+
+namespace OVR { namespace Util {
+
+static const UInt32 TIME_TO_WAIT_FOR_SETTLE_PRE_CALIBRATION = 16*10;
+static const UInt32 TIME_TO_WAIT_FOR_SETTLE_POST_CALIBRATION = 16*10;
+static const UInt32 TIME_TO_WAIT_FOR_SETTLE_POST_MEASUREMENT = 16*5;
+static const UInt32 TIME_TO_WAIT_FOR_SETTLE_POST_MEASUREMENT_RANDOMNESS = 16*5;
+static const UInt32 DEFAULT_NUMBER_OF_SAMPLES = 10; // For both color 1->2 and color 2->1 transitions.
+static const UInt32 INITIAL_SAMPLES_TO_IGNORE = 4;
+static const UInt32 TIMEOUT_WAITING_FOR_TEST_STARTED = 1000;
+static const UInt32 TIMEOUT_WAITING_FOR_COLOR_DETECTED = 4000;
+static const Color CALIBRATE_BLACK(0, 0, 0);
+static const Color CALIBRATE_WHITE(255, 255, 255);
+static const Color COLOR1(0, 0, 0);
+static const Color COLOR2(255, 255, 255);
+static const Color SENSOR_DETECT_THRESHOLD(128, 255, 255);
+static const float BIG_FLOAT = 1000000.0f;
+static const float SMALL_FLOAT = -1000000.0f;
+
+//-------------------------------------------------------------------------------------
+// ***** LatencyTest
+
+LatencyTest::LatencyTest(LatencyTestDevice* device)
+ : Handler(getThis())
+{
+ if (device != NULL)
+ {
+ SetDevice(device);
+ }
+
+ reset();
+
+ srand(Timer::GetTicksMs());
+}
+
+LatencyTest::~LatencyTest()
+{
+ clearMeasurementResults();
+}
+
+bool LatencyTest::SetDevice(LatencyTestDevice* device)
+{
+
+ if (device != Device)
+ {
+ if (device != NULL)
+ {
+ if (device->GetMessageHandler() != NULL)
+ {
+ OVR_DEBUG_LOG(
+ ("LatencyTest::AttachToDevice failed - device %p already has handler", device));
+ return false;
+ }
+ }
+
+ if (Device != NULL)
+ {
+ Device->SetMessageHandler(0);
+ }
+ Device = device;
+
+ if (Device != NULL)
+ {
+ Device->SetMessageHandler(&Handler);
+
+ // Set trigger threshold.
+ LatencyTestConfiguration configuration(SENSOR_DETECT_THRESHOLD, false); // No samples streaming.
+ Device->SetConfiguration(configuration, true);
+
+ // Set display to intial (3 dashes).
+ LatencyTestDisplay ltd(2, 0x40400040);
+ Device->SetDisplay(ltd);
+ }
+ }
+
+ return true;
+}
+
+UInt32 LatencyTest::getRandomComponent(UInt32 range)
+{
+ UInt32 val = rand() % range;
+ return val;
+}
+
+void LatencyTest::BeginTest()
+{
+ if (State == State_WaitingForButton)
+ {
+ // Set color to black and wait a while.
+ RenderColor = CALIBRATE_BLACK;
+
+ State = State_WaitingForSettlePreCalibrationColorBlack;
+ OVR_DEBUG_LOG(("State_WaitingForButton -> State_WaitingForSettlePreCalibrationColorBlack."));
+
+ setTimer(TIME_TO_WAIT_FOR_SETTLE_PRE_CALIBRATION);
+ }
+}
+
+void LatencyTest::handleMessage(const Message& msg, LatencyTestMessageType latencyTestMessage)
+{
+ // For debugging.
+/* if (msg.Type == Message_LatencyTestSamples)
+ {
+ MessageLatencyTestSamples* pSamples = (MessageLatencyTestSamples*) &msg;
+
+ if (pSamples->Samples.GetSize() > 0)
+ {
+ // Just show the first one for now.
+ Color c = pSamples->Samples[0];
+ OVR_DEBUG_LOG(("%d %d %d", c.R, c.G, c.B));
+ }
+ return;
+ }
+*/
+
+ if (latencyTestMessage == LatencyTest_Timer)
+ {
+ if (!Device)
+ {
+ reset();
+ return;
+ }
+
+ if (State == State_WaitingForSettlePreCalibrationColorBlack)
+ {
+ // Send calibrate message to device and wait a while.
+ Device->SetCalibrate(CALIBRATE_BLACK);
+
+ State = State_WaitingForSettlePostCalibrationColorBlack;
+ OVR_DEBUG_LOG(("State_WaitingForSettlePreCalibrationColorBlack -> State_WaitingForSettlePostCalibrationColorBlack."));
+
+ setTimer(TIME_TO_WAIT_FOR_SETTLE_POST_CALIBRATION);
+ }
+ else if (State == State_WaitingForSettlePostCalibrationColorBlack)
+ {
+ // Change color to white and wait a while.
+ RenderColor = CALIBRATE_WHITE;
+
+ State = State_WaitingForSettlePreCalibrationColorWhite;
+ OVR_DEBUG_LOG(("State_WaitingForSettlePostCalibrationColorBlack -> State_WaitingForSettlePreCalibrationColorWhite."));
+
+ setTimer(TIME_TO_WAIT_FOR_SETTLE_PRE_CALIBRATION);
+ }
+ else if (State == State_WaitingForSettlePreCalibrationColorWhite)
+ {
+ // Send calibrate message to device and wait a while.
+ Device->SetCalibrate(CALIBRATE_WHITE);
+
+ State = State_WaitingForSettlePostCalibrationColorWhite;
+ OVR_DEBUG_LOG(("State_WaitingForSettlePreCalibrationColorWhite -> State_WaitingForSettlePostCalibrationColorWhite."));
+
+ setTimer(TIME_TO_WAIT_FOR_SETTLE_POST_CALIBRATION);
+ }
+ else if (State == State_WaitingForSettlePostCalibrationColorWhite)
+ {
+ // Calibration is done. Switch to color 1 and wait for it to settle.
+ RenderColor = COLOR1;
+
+ State = State_WaitingForSettlePostMeasurement;
+ OVR_DEBUG_LOG(("State_WaitingForSettlePostCalibrationColorWhite -> State_WaitingForSettlePostMeasurement."));
+
+ UInt32 waitTime = TIME_TO_WAIT_FOR_SETTLE_POST_MEASUREMENT + getRandomComponent(TIME_TO_WAIT_FOR_SETTLE_POST_MEASUREMENT_RANDOMNESS);
+ setTimer(waitTime);
+ }
+ else if (State == State_WaitingForSettlePostMeasurement)
+ {
+ // Prepare for next measurement.
+
+ // Create a new result object.
+ MeasurementResult* pResult = new MeasurementResult();
+ Results.PushBack(pResult);
+
+ State = State_WaitingToTakeMeasurement;
+ OVR_DEBUG_LOG(("State_WaitingForSettlePostMeasurement -> State_WaitingToTakeMeasurement."));
+ }
+ else if (State == State_WaitingForTestStarted)
+ {
+ // We timed out waiting for 'TestStarted'. Abandon this measurement and setup for the next.
+ getActiveResult()->TimedOutWaitingForTestStarted = true;
+
+ State = State_WaitingForSettlePostMeasurement;
+ OVR_DEBUG_LOG(("** Timed out waiting for 'TestStarted'."));
+ OVR_DEBUG_LOG(("State_WaitingForTestStarted -> State_WaitingForSettlePostMeasurement."));
+
+ UInt32 waitTime = TIME_TO_WAIT_FOR_SETTLE_POST_MEASUREMENT + getRandomComponent(TIME_TO_WAIT_FOR_SETTLE_POST_MEASUREMENT_RANDOMNESS);
+ setTimer(waitTime);
+ }
+ else if (State == State_WaitingForColorDetected)
+ {
+ // We timed out waiting for 'ColorDetected'. Abandon this measurement and setup for the next.
+ getActiveResult()->TimedOutWaitingForColorDetected = true;
+
+ State = State_WaitingForSettlePostMeasurement;
+ OVR_DEBUG_LOG(("** Timed out waiting for 'ColorDetected'."));
+ OVR_DEBUG_LOG(("State_WaitingForColorDetected -> State_WaitingForSettlePostMeasurement."));
+
+ UInt32 waitTime = TIME_TO_WAIT_FOR_SETTLE_POST_MEASUREMENT + getRandomComponent(TIME_TO_WAIT_FOR_SETTLE_POST_MEASUREMENT_RANDOMNESS);
+ setTimer(waitTime);
+ }
+ }
+ else if (latencyTestMessage == LatencyTest_ProcessInputs)
+ {
+ if (State == State_WaitingToTakeMeasurement)
+ {
+ if (!Device)
+ {
+ reset();
+ return;
+ }
+
+ // Send 'StartTest' feature report with opposite target color.
+ if (RenderColor == COLOR1)
+ {
+ RenderColor = COLOR2;
+ }
+ else
+ {
+ RenderColor = COLOR1;
+ }
+
+ getActiveResult()->TargetColor = RenderColor;
+
+ // Record time so we can determine usb roundtrip time.
+ getActiveResult()->StartTestTicksMicroS = Timer::GetTicks();
+
+ Device->SetStartTest(RenderColor);
+
+ State = State_WaitingForTestStarted;
+ OVR_DEBUG_LOG(("State_WaitingToTakeMeasurement -> State_WaitingForTestStarted."));
+
+ setTimer(TIMEOUT_WAITING_FOR_TEST_STARTED);
+
+ LatencyTestDisplay ltd(2, 0x40090040);
+ Device->SetDisplay(ltd);
+ }
+ }
+ else if (msg.Type == Message_LatencyTestButton)
+ {
+ BeginTest();
+ }
+ else if (msg.Type == Message_LatencyTestStarted)
+ {
+ if (State == State_WaitingForTestStarted)
+ {
+ clearTimer();
+
+ // Record time so we can determine usb roundtrip time.
+ getActiveResult()->TestStartedTicksMicroS = Timer::GetTicks();
+
+ State = State_WaitingForColorDetected;
+ OVR_DEBUG_LOG(("State_WaitingForTestStarted -> State_WaitingForColorDetected."));
+
+ setTimer(TIMEOUT_WAITING_FOR_COLOR_DETECTED);
+ }
+ }
+ else if (msg.Type == Message_LatencyTestColorDetected)
+ {
+ if (State == State_WaitingForColorDetected)
+ {
+ // Record time to detect color.
+ MessageLatencyTestColorDetected* pDetected = (MessageLatencyTestColorDetected*) &msg;
+ UInt16 elapsedTime = pDetected->Elapsed;
+ OVR_DEBUG_LOG(("Time to 'ColorDetected' = %d", elapsedTime));
+
+ getActiveResult()->DeviceMeasuredElapsedMilliS = elapsedTime;
+
+ if (areResultsComplete())
+ {
+ // We're done.
+ processResults();
+ reset();
+ }
+ else
+ {
+ // Run another measurement.
+ State = State_WaitingForSettlePostMeasurement;
+ OVR_DEBUG_LOG(("State_WaitingForColorDetected -> State_WaitingForSettlePostMeasurement."));
+
+ UInt32 waitTime = TIME_TO_WAIT_FOR_SETTLE_POST_MEASUREMENT + getRandomComponent(TIME_TO_WAIT_FOR_SETTLE_POST_MEASUREMENT_RANDOMNESS);
+ setTimer(waitTime);
+
+ LatencyTestDisplay ltd(2, 0x40400040);
+ Device->SetDisplay(ltd);
+ }
+ }
+ }
+ else if (msg.Type == Message_DeviceRemoved)
+ {
+ reset();
+ }
+}
+
+LatencyTest::MeasurementResult* LatencyTest::getActiveResult()
+{
+ OVR_ASSERT(!Results.IsEmpty());
+ return Results.GetLast();
+}
+
+void LatencyTest::setTimer(UInt32 timeMilliS)
+{
+ ActiveTimerMilliS = timeMilliS;
+}
+
+void LatencyTest::clearTimer()
+{
+ ActiveTimerMilliS = 0;
+}
+
+void LatencyTest::reset()
+{
+ clearMeasurementResults();
+ State = State_WaitingForButton;
+
+ HaveOldTime = false;
+ ActiveTimerMilliS = 0;
+}
+
+void LatencyTest::clearMeasurementResults()
+{
+ while(!Results.IsEmpty())
+ {
+ MeasurementResult* pElem = Results.GetFirst();
+ pElem->RemoveNode();
+ delete pElem;
+ }
+}
+
+LatencyTest::LatencyTestHandler::~LatencyTestHandler()
+{
+ RemoveHandlerFromDevices();
+}
+
+void LatencyTest::LatencyTestHandler::OnMessage(const Message& msg)
+{
+ pLatencyTestUtil->handleMessage(msg);
+}
+
+void LatencyTest::ProcessInputs()
+{
+ updateForTimeouts();
+ handleMessage(Message(), LatencyTest_ProcessInputs);
+}
+
+bool LatencyTest::DisplayScreenColor(Color& colorToDisplay)
+{
+ updateForTimeouts();
+
+ if (State == State_WaitingForButton)
+ {
+ return false;
+ }
+
+ colorToDisplay = RenderColor;
+ return true;
+}
+
+const char* LatencyTest::GetResultsString()
+{
+ if (!ResultsString.IsEmpty() && ReturnedResultString != ResultsString.ToCStr())
+ {
+ ReturnedResultString = ResultsString;
+ return ReturnedResultString.ToCStr();
+ }
+
+ return NULL;
+}
+
+bool LatencyTest::areResultsComplete()
+{
+ UInt32 initialMeasurements = 0;
+
+ UInt32 measurements1to2 = 0;
+ UInt32 measurements2to1 = 0;
+
+ MeasurementResult* pCurr = Results.GetFirst();
+ while(true)
+ {
+ // Process.
+ if (!pCurr->TimedOutWaitingForTestStarted &&
+ !pCurr->TimedOutWaitingForColorDetected)
+ {
+ initialMeasurements++;
+
+ if (initialMeasurements > INITIAL_SAMPLES_TO_IGNORE)
+ {
+ if (pCurr->TargetColor == COLOR2)
+ {
+ measurements1to2++;
+ }
+ else
+ {
+ measurements2to1++;
+ }
+ }
+ }
+
+ if (Results.IsLast(pCurr))
+ {
+ break;
+ }
+ pCurr = Results.GetNext(pCurr);
+ }
+
+ if (measurements1to2 >= DEFAULT_NUMBER_OF_SAMPLES &&
+ measurements2to1 >= DEFAULT_NUMBER_OF_SAMPLES)
+ {
+ return true;
+ }
+
+ return false;
+}
+
+void LatencyTest::processResults()
+{
+
+ UInt32 minTime1To2 = UINT_MAX;
+ UInt32 maxTime1To2 = 0;
+ float averageTime1To2 = 0.0f;
+ UInt32 minTime2To1 = UINT_MAX;
+ UInt32 maxTime2To1 = 0;
+ float averageTime2To1 = 0.0f;
+
+ float minUSBTripMilliS = BIG_FLOAT;
+ float maxUSBTripMilliS = SMALL_FLOAT;
+ float averageUSBTripMilliS = 0.0f;
+ UInt32 countUSBTripTime = 0;
+
+ UInt32 measurementsCount = 0;
+ UInt32 measurements1to2 = 0;
+ UInt32 measurements2to1 = 0;
+
+ MeasurementResult* pCurr = Results.GetFirst();
+ UInt32 count = 0;
+ while(true)
+ {
+ count++;
+
+ if (!pCurr->TimedOutWaitingForTestStarted &&
+ !pCurr->TimedOutWaitingForColorDetected)
+ {
+ measurementsCount++;
+
+ if (measurementsCount > INITIAL_SAMPLES_TO_IGNORE)
+ {
+ if (pCurr->TargetColor == COLOR2)
+ {
+ measurements1to2++;
+
+ if (measurements1to2 <= DEFAULT_NUMBER_OF_SAMPLES)
+ {
+ UInt32 elapsed = pCurr->DeviceMeasuredElapsedMilliS;
+
+ minTime1To2 = Alg::Min(elapsed, minTime1To2);
+ maxTime1To2 = Alg::Max(elapsed, maxTime1To2);
+
+ averageTime1To2 += (float) elapsed;
+ }
+ }
+ else
+ {
+ measurements2to1++;
+
+ if (measurements2to1 <= DEFAULT_NUMBER_OF_SAMPLES)
+ {
+ UInt32 elapsed = pCurr->DeviceMeasuredElapsedMilliS;
+
+ minTime2To1 = Alg::Min(elapsed, minTime2To1);
+ maxTime2To1 = Alg::Max(elapsed, maxTime2To1);
+
+ averageTime2To1 += (float) elapsed;
+ }
+ }
+
+ float usbRountripElapsedMilliS = 0.001f * (float) (pCurr->TestStartedTicksMicroS - pCurr->StartTestTicksMicroS);
+ minUSBTripMilliS = Alg::Min(usbRountripElapsedMilliS, minUSBTripMilliS);
+ maxUSBTripMilliS = Alg::Max(usbRountripElapsedMilliS, maxUSBTripMilliS);
+ averageUSBTripMilliS += usbRountripElapsedMilliS;
+ countUSBTripTime++;
+ }
+ }
+
+ if (measurements1to2 >= DEFAULT_NUMBER_OF_SAMPLES &&
+ measurements2to1 >= DEFAULT_NUMBER_OF_SAMPLES)
+ {
+ break;
+ }
+
+ if (Results.IsLast(pCurr))
+ {
+ break;
+ }
+ pCurr = Results.GetNext(pCurr);
+ }
+
+ averageTime1To2 /= (float) DEFAULT_NUMBER_OF_SAMPLES;
+ averageTime2To1 /= (float) DEFAULT_NUMBER_OF_SAMPLES;
+
+ averageUSBTripMilliS /= countUSBTripTime;
+
+ float finalResult = 0.5f * (averageTime1To2 + averageTime2To1);
+ finalResult += averageUSBTripMilliS;
+
+ ResultsString.Clear();
+ ResultsString.AppendFormat("RESULT=%.1f (add half Tracker period) [b->w %d|%.1f|%d] [w->b %d|%.1f|%d] [usb rndtrp %.1f|%.1f|%.1f] [cnt %d] [tmouts %d]",
+ finalResult,
+ minTime1To2, averageTime1To2, maxTime1To2,
+ minTime2To1, averageTime2To1, maxTime2To1,
+ minUSBTripMilliS, averageUSBTripMilliS, maxUSBTripMilliS,
+ DEFAULT_NUMBER_OF_SAMPLES*2, count - measurementsCount);
+
+ // Display result on latency tester display.
+ LatencyTestDisplay ltd(1, (int)finalResult);
+ Device->SetDisplay(ltd);
+}
+
+void LatencyTest::updateForTimeouts()
+{
+ if (!HaveOldTime)
+ {
+ HaveOldTime = true;
+ OldTime = Timer::GetTicksMs();
+ return;
+ }
+
+ UInt32 newTime = Timer::GetTicksMs();
+ UInt32 elapsedMilliS = newTime - OldTime;
+ if (newTime < OldTime)
+ {
+ elapsedMilliS = OldTime - newTime;
+ elapsedMilliS = UINT_MAX - elapsedMilliS;
+ }
+ OldTime = newTime;
+
+ elapsedMilliS = Alg::Min(elapsedMilliS, (UInt32) 100); // Clamp at 100mS in case we're not being called very often.
+
+
+ if (ActiveTimerMilliS == 0)
+ {
+ return;
+ }
+
+ if (elapsedMilliS >= ActiveTimerMilliS)
+ {
+ ActiveTimerMilliS = 0;
+ handleMessage(Message(), LatencyTest_Timer);
+ return;
+ }
+
+ ActiveTimerMilliS -= elapsedMilliS;
+}
+
+}} // namespace OVR::Util
diff --git a/LibOVR/Src/Util/Util_LatencyTest.h b/LibOVR/Src/Util/Util_LatencyTest.h
index 47f98f7..a01864e 100644
--- a/LibOVR/Src/Util/Util_LatencyTest.h
+++ b/LibOVR/Src/Util/Util_LatencyTest.h
@@ -1,160 +1,160 @@
-/************************************************************************************
-
-PublicHeader: OVR.h
-Filename : Util_LatencyTest.h
-Content : Wraps the lower level LatencyTesterDevice and adds functionality.
-Created : February 14, 2013
-Authors : Lee Cooper
-
-Copyright : Copyright 2013 Oculus VR, Inc. All Rights reserved.
-
-Use of this software is subject to the terms of the Oculus license
-agreement provided at the time of installation or download, or which
-otherwise accompanies this software in either electronic or hard copy form.
-
-*************************************************************************************/
-
-#ifndef OVR_Util_LatencyTest_h
-#define OVR_Util_LatencyTest_h
-
-#include "../OVR_Device.h"
-
-#include "../Kernel/OVR_String.h"
-#include "../Kernel/OVR_List.h"
-
-namespace OVR { namespace Util {
-
-
-//-------------------------------------------------------------------------------------
-// ***** LatencyTest
-//
-// LatencyTest utility class wraps the low level LatencyTestDevice and manages the scheduling
-// of a latency test. A single test is composed of a series of individual latency measurements
-// which are used to derive min, max, and an average latency value.
-//
-// Developers are required to call the following methods:
-// SetDevice - Sets the LatencyTestDevice to be used for the tests.
-// ProcessInputs - This should be called at the same place in the code where the game engine
-// reads the headset orientation from LibOVR (typically done by calling
-// 'GetOrientation' on the SensorFusion object). Calling this at the right time
-// enables us to measure the same latency that occurs for headset orientation
-// changes.
-// DisplayScreenColor - The latency tester works by sensing the color of the pixels directly
-// beneath it. The color of these pixels can be set by drawing a small
-// quad at the end of the rendering stage. The quad should be small
-// such that it doesn't significantly impact the rendering of the scene,
-// but large enough to be 'seen' by the sensor. See the SDK
-// documentation for more information.
-// GetResultsString - Call this to get a string containing the most recent results.
-// If the string has already been gotten then NULL will be returned.
-// The string pointer will remain valid until the next time this
-// method is called.
-//
-
-class LatencyTest : public NewOverrideBase
-{
-public:
- LatencyTest(LatencyTestDevice* device = NULL);
- ~LatencyTest();
-
- // Set the Latency Tester device that we'll use to send commands to and receive
- // notification messages from.
- bool SetDevice(LatencyTestDevice* device);
-
- // Returns true if this LatencyTestUtil has a Latency Tester device.
- bool HasDevice() const
- { return Handler.IsHandlerInstalled(); }
-
- void ProcessInputs();
- bool DisplayScreenColor(Color& colorToDisplay);
- const char* GetResultsString();
-
- // Begin test. Equivalent to pressing the button on the latency tester.
- void BeginTest();
-
-private:
- LatencyTest* getThis() { return this; }
-
- enum LatencyTestMessageType
- {
- LatencyTest_None,
- LatencyTest_Timer,
- LatencyTest_ProcessInputs,
- };
-
- UInt32 getRandomComponent(UInt32 range);
- void handleMessage(const Message& msg, LatencyTestMessageType latencyTestMessage = LatencyTest_None);
- void reset();
- void setTimer(UInt32 timeMilliS);
- void clearTimer();
-
- class LatencyTestHandler : public MessageHandler
- {
- LatencyTest* pLatencyTestUtil;
- public:
- LatencyTestHandler(LatencyTest* latencyTester) : pLatencyTestUtil(latencyTester) { }
- ~LatencyTestHandler();
-
- virtual void OnMessage(const Message& msg);
- };
-
- bool areResultsComplete();
- void processResults();
- void updateForTimeouts();
-
- Ptr<LatencyTestDevice> Device;
- LatencyTestHandler Handler;
-
- enum TesterState
- {
- State_WaitingForButton,
- State_WaitingForSettlePreCalibrationColorBlack,
- State_WaitingForSettlePostCalibrationColorBlack,
- State_WaitingForSettlePreCalibrationColorWhite,
- State_WaitingForSettlePostCalibrationColorWhite,
- State_WaitingToTakeMeasurement,
- State_WaitingForTestStarted,
- State_WaitingForColorDetected,
- State_WaitingForSettlePostMeasurement
- };
- TesterState State;
-
- bool HaveOldTime;
- UInt32 OldTime;
- UInt32 ActiveTimerMilliS;
-
- Color RenderColor;
-
- struct MeasurementResult : public ListNode<MeasurementResult>, public NewOverrideBase
- {
- MeasurementResult()
- : DeviceMeasuredElapsedMilliS(0),
- TimedOutWaitingForTestStarted(false),
- TimedOutWaitingForColorDetected(false),
- StartTestTicksMicroS(0),
- TestStartedTicksMicroS(0)
- {}
-
- Color TargetColor;
-
- UInt32 DeviceMeasuredElapsedMilliS;
-
- bool TimedOutWaitingForTestStarted;
- bool TimedOutWaitingForColorDetected;
-
- UInt64 StartTestTicksMicroS;
- UInt64 TestStartedTicksMicroS;
- };
-
- List<MeasurementResult> Results;
- void clearMeasurementResults();
-
- MeasurementResult* getActiveResult();
-
- StringBuffer ResultsString;
- String ReturnedResultString;
-};
-
-}} // namespace OVR::Util
-
-#endif // OVR_Util_LatencyTest_h
+/************************************************************************************
+
+PublicHeader: OVR.h
+Filename : Util_LatencyTest.h
+Content : Wraps the lower level LatencyTesterDevice and adds functionality.
+Created : February 14, 2013
+Authors : Lee Cooper
+
+Copyright : Copyright 2013 Oculus VR, Inc. All Rights reserved.
+
+Use of this software is subject to the terms of the Oculus license
+agreement provided at the time of installation or download, or which
+otherwise accompanies this software in either electronic or hard copy form.
+
+*************************************************************************************/
+
+#ifndef OVR_Util_LatencyTest_h
+#define OVR_Util_LatencyTest_h
+
+#include "../OVR_Device.h"
+
+#include "../Kernel/OVR_String.h"
+#include "../Kernel/OVR_List.h"
+
+namespace OVR { namespace Util {
+
+
+//-------------------------------------------------------------------------------------
+// ***** LatencyTest
+//
+// LatencyTest utility class wraps the low level LatencyTestDevice and manages the scheduling
+// of a latency test. A single test is composed of a series of individual latency measurements
+// which are used to derive min, max, and an average latency value.
+//
+// Developers are required to call the following methods:
+// SetDevice - Sets the LatencyTestDevice to be used for the tests.
+// ProcessInputs - This should be called at the same place in the code where the game engine
+// reads the headset orientation from LibOVR (typically done by calling
+// 'GetOrientation' on the SensorFusion object). Calling this at the right time
+// enables us to measure the same latency that occurs for headset orientation
+// changes.
+// DisplayScreenColor - The latency tester works by sensing the color of the pixels directly
+// beneath it. The color of these pixels can be set by drawing a small
+// quad at the end of the rendering stage. The quad should be small
+// such that it doesn't significantly impact the rendering of the scene,
+// but large enough to be 'seen' by the sensor. See the SDK
+// documentation for more information.
+// GetResultsString - Call this to get a string containing the most recent results.
+// If the string has already been gotten then NULL will be returned.
+// The string pointer will remain valid until the next time this
+// method is called.
+//
+
+class LatencyTest : public NewOverrideBase
+{
+public:
+ LatencyTest(LatencyTestDevice* device = NULL);
+ ~LatencyTest();
+
+ // Set the Latency Tester device that we'll use to send commands to and receive
+ // notification messages from.
+ bool SetDevice(LatencyTestDevice* device);
+
+ // Returns true if this LatencyTestUtil has a Latency Tester device.
+ bool HasDevice() const
+ { return Handler.IsHandlerInstalled(); }
+
+ void ProcessInputs();
+ bool DisplayScreenColor(Color& colorToDisplay);
+ const char* GetResultsString();
+
+ // Begin test. Equivalent to pressing the button on the latency tester.
+ void BeginTest();
+
+private:
+ LatencyTest* getThis() { return this; }
+
+ enum LatencyTestMessageType
+ {
+ LatencyTest_None,
+ LatencyTest_Timer,
+ LatencyTest_ProcessInputs,
+ };
+
+ UInt32 getRandomComponent(UInt32 range);
+ void handleMessage(const Message& msg, LatencyTestMessageType latencyTestMessage = LatencyTest_None);
+ void reset();
+ void setTimer(UInt32 timeMilliS);
+ void clearTimer();
+
+ class LatencyTestHandler : public MessageHandler
+ {
+ LatencyTest* pLatencyTestUtil;
+ public:
+ LatencyTestHandler(LatencyTest* latencyTester) : pLatencyTestUtil(latencyTester) { }
+ ~LatencyTestHandler();
+
+ virtual void OnMessage(const Message& msg);
+ };
+
+ bool areResultsComplete();
+ void processResults();
+ void updateForTimeouts();
+
+ Ptr<LatencyTestDevice> Device;
+ LatencyTestHandler Handler;
+
+ enum TesterState
+ {
+ State_WaitingForButton,
+ State_WaitingForSettlePreCalibrationColorBlack,
+ State_WaitingForSettlePostCalibrationColorBlack,
+ State_WaitingForSettlePreCalibrationColorWhite,
+ State_WaitingForSettlePostCalibrationColorWhite,
+ State_WaitingToTakeMeasurement,
+ State_WaitingForTestStarted,
+ State_WaitingForColorDetected,
+ State_WaitingForSettlePostMeasurement
+ };
+ TesterState State;
+
+ bool HaveOldTime;
+ UInt32 OldTime;
+ UInt32 ActiveTimerMilliS;
+
+ Color RenderColor;
+
+ struct MeasurementResult : public ListNode<MeasurementResult>, public NewOverrideBase
+ {
+ MeasurementResult()
+ : DeviceMeasuredElapsedMilliS(0),
+ TimedOutWaitingForTestStarted(false),
+ TimedOutWaitingForColorDetected(false),
+ StartTestTicksMicroS(0),
+ TestStartedTicksMicroS(0)
+ {}
+
+ Color TargetColor;
+
+ UInt32 DeviceMeasuredElapsedMilliS;
+
+ bool TimedOutWaitingForTestStarted;
+ bool TimedOutWaitingForColorDetected;
+
+ UInt64 StartTestTicksMicroS;
+ UInt64 TestStartedTicksMicroS;
+ };
+
+ List<MeasurementResult> Results;
+ void clearMeasurementResults();
+
+ MeasurementResult* getActiveResult();
+
+ StringBuffer ResultsString;
+ String ReturnedResultString;
+};
+
+}} // namespace OVR::Util
+
+#endif // OVR_Util_LatencyTest_h
diff --git a/LibOVR/Src/Util/Util_MagCalibration.cpp b/LibOVR/Src/Util/Util_MagCalibration.cpp
index f3e72f5..c537154 100644
--- a/LibOVR/Src/Util/Util_MagCalibration.cpp
+++ b/LibOVR/Src/Util/Util_MagCalibration.cpp
@@ -1,180 +1,180 @@
-/************************************************************************************
-
-Filename : Util_MagCalibration.cpp
-Content : Procedures for calibrating the magnetometer
-Created : April 16, 2013
-Authors : Steve LaValle, Andrew Reisse
-
-Copyright : Copyright 2013 Oculus VR, Inc. All Rights reserved.
-
-Use of this software is subject to the terms of the Oculus license
-agreement provided at the time of installation or download, or which
-otherwise accompanies this software in either electronic or hard copy form.
-
-*************************************************************************************/
-
-#include "Util_MagCalibration.h"
-
-namespace OVR { namespace Util {
-
-void MagCalibration::BeginAutoCalibration(SensorFusion& sf)
-{
- Status = Mag_AutoCalibrating;
- // This is a "hard" reset of the mag, so need to clear stored values
- sf.ClearMagCalibration();
- SampleCount = 0;
-}
-
-unsigned MagCalibration::UpdateAutoCalibration(SensorFusion& sf)
-{
- if (Status != Mag_AutoCalibrating)
- return Status;
-
- Quatf q = sf.GetOrientation();
- Vector3f m = sf.GetMagnetometer();
-
- InsertIfAcceptable(q, m);
-
- if ((SampleCount == 4) && (Status == Mag_AutoCalibrating))
- SetCalibration(sf);
-
- return Status;
-
-}
-
-void MagCalibration::BeginManualCalibration(SensorFusion& sf)
-{
- Status = Mag_ManuallyCalibrating;
- sf.ClearMagCalibration();
- SampleCount = 0;
-}
-
-bool MagCalibration::IsAcceptableSample(const Quatf& q, const Vector3f& m)
-{
- switch (SampleCount)
- {
- // Initial sample is always acceptable
- case 0:
- return true;
- break;
- case 1:
- return (q.DistanceSq(QuatSamples[0]) > MinQuatDistanceSq)&&
- ((m - MagSamples[0]).LengthSq() > MinMagDistanceSq);
- break;
- case 2:
- return (q.DistanceSq(QuatSamples[0]) > MinQuatDistanceSq)&&
- (q.DistanceSq(QuatSamples[1]) > MinQuatDistanceSq)&&
- ((m - MagSamples[0]).LengthSq() > MinMagDistanceSq)&&
- ((m - MagSamples[1]).LengthSq() > MinMagDistanceSq);
- break;
- case 3:
- return (q.DistanceSq(QuatSamples[0]) > MinQuatDistanceSq)&&
- (q.DistanceSq(QuatSamples[1]) > MinQuatDistanceSq)&&
- (q.DistanceSq(QuatSamples[2]) > MinQuatDistanceSq)&&
- ((PointToPlaneDistance(MagSamples[0],MagSamples[1],MagSamples[2],m) > MinMagDistance)||
- (PointToPlaneDistance(MagSamples[1],MagSamples[2],m,MagSamples[0]) > MinMagDistance)||
- (PointToPlaneDistance(MagSamples[2],m,MagSamples[0],MagSamples[1]) > MinMagDistance)||
- (PointToPlaneDistance(m,MagSamples[0],MagSamples[1],MagSamples[2]) > MinMagDistance));
- }
-
- return false;
-}
-
-
-bool MagCalibration::InsertIfAcceptable(const Quatf& q, const Vector3f& m)
-{
- if (IsAcceptableSample(q, m))
- {
- MagSamples[SampleCount] = m;
- QuatSamples[SampleCount] = q;
- SampleCount++;
- return true;
- }
-
- return false;
-}
-
-
-bool MagCalibration::SetCalibration(SensorFusion& sf)
-{
- if (SampleCount < 4)
- 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;
- sf.SetMagCalibration(calMat);
- Status = Mag_Calibrated;
- //LogText("MagCenter: %f %f %f\n",MagCenter.x,MagCenter.y,MagCenter.z);
-
- return true;
-}
-
-
-// Calculate the center of a sphere that passes through p1, p2, p3, p4
-Vector3f MagCalibration::CalculateSphereCenter(const Vector3f& p1, const Vector3f& p2,
- const Vector3f& p3, const Vector3f& p4)
-{
- Matrix4f A;
- int i;
- Vector3f p[4];
- p[0] = p1;
- p[1] = p2;
- p[2] = p3;
- p[3] = p4;
-
- for (i = 0; i < 4; i++)
- {
- A.M[i][0] = p[i].x;
- A.M[i][1] = p[i].y;
- A.M[i][2] = p[i].z;
- A.M[i][3] = 1.0f;
- }
- float m11 = A.Determinant();
- OVR_ASSERT(m11 != 0.0f);
-
- for (i = 0; i < 4; i++)
- {
- A.M[i][0] = p[i].x*p[i].x + p[i].y*p[i].y + p[i].z*p[i].z;
- A.M[i][1] = p[i].y;
- A.M[i][2] = p[i].z;
- A.M[i][3] = 1.0f;
- }
- float m12 = A.Determinant();
-
- for (i = 0; i < 4; i++)
- {
- A.M[i][0] = p[i].x*p[i].x + p[i].y*p[i].y + p[i].z*p[i].z;
- A.M[i][1] = p[i].x;
- A.M[i][2] = p[i].z;
- A.M[i][3] = 1.0f;
- }
- float m13 = A.Determinant();
-
- for (i = 0; i < 4; i++)
- {
- A.M[i][0] = p[i].x*p[i].x + p[i].y*p[i].y + p[i].z*p[i].z;
- A.M[i][1] = p[i].x;
- A.M[i][2] = p[i].y;
- A.M[i][3] = 1.0f;
- }
- float m14 = A.Determinant();
-
- float c = 0.5f / m11;
- return Vector3f(c*m12, -c*m13, c*m14);
-}
-
-// Distance from p4 to the nearest point on a plane through p1, p2, p3
-float MagCalibration::PointToPlaneDistance(const Vector3f& p1, const Vector3f& p2,
- const Vector3f& p3, const Vector3f& p4)
-{
- Vector3f v1 = p1 - p2;
- Vector3f v2 = p1 - p3;
- Vector3f planeNormal = v1.Cross(v2);
- planeNormal.Normalize();
- return (fabs((planeNormal * p4) - planeNormal * p1));
-}
-
-}}
+/************************************************************************************
+
+Filename : Util_MagCalibration.cpp
+Content : Procedures for calibrating the magnetometer
+Created : April 16, 2013
+Authors : Steve LaValle, Andrew Reisse
+
+Copyright : Copyright 2013 Oculus VR, Inc. All Rights reserved.
+
+Use of this software is subject to the terms of the Oculus license
+agreement provided at the time of installation or download, or which
+otherwise accompanies this software in either electronic or hard copy form.
+
+*************************************************************************************/
+
+#include "Util_MagCalibration.h"
+
+namespace OVR { namespace Util {
+
+void MagCalibration::BeginAutoCalibration(SensorFusion& sf)
+{
+ Stat = Mag_AutoCalibrating;
+ // This is a "hard" reset of the mag, so need to clear stored values
+ sf.ClearMagCalibration();
+ SampleCount = 0;
+}
+
+unsigned MagCalibration::UpdateAutoCalibration(SensorFusion& sf)
+{
+ if (Stat != Mag_AutoCalibrating)
+ return Stat;
+
+ Quatf q = sf.GetOrientation();
+ Vector3f m = sf.GetMagnetometer();
+
+ InsertIfAcceptable(q, m);
+
+ if ((SampleCount == 4) && (Stat == Mag_AutoCalibrating))
+ SetCalibration(sf);
+
+ return Stat;
+
+}
+
+void MagCalibration::BeginManualCalibration(SensorFusion& sf)
+{
+ Stat = Mag_ManuallyCalibrating;
+ sf.ClearMagCalibration();
+ SampleCount = 0;
+}
+
+bool MagCalibration::IsAcceptableSample(const Quatf& q, const Vector3f& m)
+{
+ switch (SampleCount)
+ {
+ // Initial sample is always acceptable
+ case 0:
+ return true;
+ break;
+ case 1:
+ return (q.DistanceSq(QuatSamples[0]) > MinQuatDistanceSq)&&
+ ((m - MagSamples[0]).LengthSq() > MinMagDistanceSq);
+ break;
+ case 2:
+ return (q.DistanceSq(QuatSamples[0]) > MinQuatDistanceSq)&&
+ (q.DistanceSq(QuatSamples[1]) > MinQuatDistanceSq)&&
+ ((m - MagSamples[0]).LengthSq() > MinMagDistanceSq)&&
+ ((m - MagSamples[1]).LengthSq() > MinMagDistanceSq);
+ break;
+ case 3:
+ return (q.DistanceSq(QuatSamples[0]) > MinQuatDistanceSq)&&
+ (q.DistanceSq(QuatSamples[1]) > MinQuatDistanceSq)&&
+ (q.DistanceSq(QuatSamples[2]) > MinQuatDistanceSq)&&
+ ((PointToPlaneDistance(MagSamples[0],MagSamples[1],MagSamples[2],m) > MinMagDistance)||
+ (PointToPlaneDistance(MagSamples[1],MagSamples[2],m,MagSamples[0]) > MinMagDistance)||
+ (PointToPlaneDistance(MagSamples[2],m,MagSamples[0],MagSamples[1]) > MinMagDistance)||
+ (PointToPlaneDistance(m,MagSamples[0],MagSamples[1],MagSamples[2]) > MinMagDistance));
+ }
+
+ return false;
+}
+
+
+bool MagCalibration::InsertIfAcceptable(const Quatf& q, const Vector3f& m)
+{
+ if (IsAcceptableSample(q, m))
+ {
+ MagSamples[SampleCount] = m;
+ QuatSamples[SampleCount] = q;
+ SampleCount++;
+ return true;
+ }
+
+ return false;
+}
+
+
+bool MagCalibration::SetCalibration(SensorFusion& sf)
+{
+ if (SampleCount < 4)
+ 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;
+ sf.SetMagCalibration(calMat);
+ Stat = Mag_Calibrated;
+ //LogText("MagCenter: %f %f %f\n",MagCenter.x,MagCenter.y,MagCenter.z);
+
+ return true;
+}
+
+
+// Calculate the center of a sphere that passes through p1, p2, p3, p4
+Vector3f MagCalibration::CalculateSphereCenter(const Vector3f& p1, const Vector3f& p2,
+ const Vector3f& p3, const Vector3f& p4)
+{
+ Matrix4f A;
+ int i;
+ Vector3f p[4];
+ p[0] = p1;
+ p[1] = p2;
+ p[2] = p3;
+ p[3] = p4;
+
+ for (i = 0; i < 4; i++)
+ {
+ A.M[i][0] = p[i].x;
+ A.M[i][1] = p[i].y;
+ A.M[i][2] = p[i].z;
+ A.M[i][3] = 1.0f;
+ }
+ float m11 = A.Determinant();
+ OVR_ASSERT(m11 != 0.0f);
+
+ for (i = 0; i < 4; i++)
+ {
+ A.M[i][0] = p[i].x*p[i].x + p[i].y*p[i].y + p[i].z*p[i].z;
+ A.M[i][1] = p[i].y;
+ A.M[i][2] = p[i].z;
+ A.M[i][3] = 1.0f;
+ }
+ float m12 = A.Determinant();
+
+ for (i = 0; i < 4; i++)
+ {
+ A.M[i][0] = p[i].x*p[i].x + p[i].y*p[i].y + p[i].z*p[i].z;
+ A.M[i][1] = p[i].x;
+ A.M[i][2] = p[i].z;
+ A.M[i][3] = 1.0f;
+ }
+ float m13 = A.Determinant();
+
+ for (i = 0; i < 4; i++)
+ {
+ A.M[i][0] = p[i].x*p[i].x + p[i].y*p[i].y + p[i].z*p[i].z;
+ A.M[i][1] = p[i].x;
+ A.M[i][2] = p[i].y;
+ A.M[i][3] = 1.0f;
+ }
+ float m14 = A.Determinant();
+
+ float c = 0.5f / m11;
+ return Vector3f(c*m12, -c*m13, c*m14);
+}
+
+// Distance from p4 to the nearest point on a plane through p1, p2, p3
+float MagCalibration::PointToPlaneDistance(const Vector3f& p1, const Vector3f& p2,
+ const Vector3f& p3, const Vector3f& p4)
+{
+ Vector3f v1 = p1 - p2;
+ Vector3f v2 = p1 - p3;
+ Vector3f planeNormal = v1.Cross(v2);
+ planeNormal.Normalize();
+ return (fabs((planeNormal * p4) - planeNormal * p1));
+}
+
+}}
diff --git a/LibOVR/Src/Util/Util_MagCalibration.h b/LibOVR/Src/Util/Util_MagCalibration.h
index 9371125..fd26d22 100644
--- a/LibOVR/Src/Util/Util_MagCalibration.h
+++ b/LibOVR/Src/Util/Util_MagCalibration.h
@@ -1,115 +1,121 @@
-/************************************************************************************
-
-PublicHeader: OVR.h
-Filename : Util_MagCalibration.h
-Content : Procedures for calibrating the magnetometer
-Created : April 16, 2013
-Authors : Steve LaValle, Andrew Reisse
-
-Copyright : Copyright 2013 Oculus VR, Inc. All Rights reserved.
-
-Use of this software is subject to the terms of the Oculus license
-agreement provided at the time of installation or download, or which
-otherwise accompanies this software in either electronic or hard copy form.
-
-*************************************************************************************/
-
-#ifndef OVR_Util_MagCalibration_h
-#define OVR_Util_MagCalibration_h
-
-#include "../OVR_SensorFusion.h"
-#include "../Kernel/OVR_String.h"
-#include "../Kernel/OVR_Log.h"
-
-namespace OVR { namespace Util {
-
-class MagCalibration
-{
-public:
- enum MagStatus
- {
- Mag_Uninitialized = 0,
- Mag_AutoCalibrating = 1,
- Mag_ManuallyCalibrating = 2,
- Mag_Calibrated = 3,
- };
-
- MagCalibration() :
- Status(Mag_Uninitialized),
- MinMagDistance(0.3f), MinQuatDistance(0.5f),
- SampleCount(0)
- {
- MinMagDistanceSq = MinMagDistance * MinMagDistance;
- MinQuatDistanceSq = MinQuatDistance * MinQuatDistance;
- }
-
- // Methods that are useful for either auto or manual calibration
- bool IsUnitialized() const { return Status == Mag_Uninitialized; }
- bool IsCalibrated() const { return Status == Mag_Calibrated; }
- int NumberOfSamples() const { return SampleCount; }
- int RequiredSampleCount() const { return 4; }
- void ClearCalibration(SensorFusion& sf)
- {
- Status = Mag_Uninitialized;
- SampleCount = 0;
- sf.ClearMagCalibration();
- };
-
- // Methods for automatic magnetometer calibration
- void BeginAutoCalibration(SensorFusion& sf);
- unsigned UpdateAutoCalibration(SensorFusion& sf);
- bool IsAutoCalibrating() const { return Status == Mag_AutoCalibrating; }
-
- // Methods for building a manual (user-guided) calibraton procedure
- void BeginManualCalibration(SensorFusion& sf);
- bool IsAcceptableSample(const Quatf& q, const Vector3f& m);
- bool InsertIfAcceptable(const Quatf& q, const Vector3f& m);
- // Returns true if successful, requiring that SampleCount = 4
- bool SetCalibration(SensorFusion& sf);
- bool IsManuallyCalibrating() const { return Status == Mag_ManuallyCalibrating; }
-
- // This is the minimum acceptable distance (Euclidean) between raw
- // magnetometer values to be acceptable for usage in calibration.
- void SetMinMagDistance(float dist)
- {
- MinMagDistance = dist;
- MinMagDistanceSq = MinMagDistance * MinMagDistance;
- }
-
- // The minimum acceptable distance (4D Euclidean) between orientations
- // to be acceptable for calibration usage.
- void SetMinQuatDistance(float dist)
- {
- MinQuatDistance = dist;
- MinQuatDistanceSq = MinQuatDistance * MinQuatDistance;
- }
-
- // A result of the calibration, which is the center of a sphere that
- // roughly approximates the magnetometer data.
- Vector3f GetMagCenter() const { return MagCenter; }
-
-private:
- // Determine the unique sphere through 4 non-coplanar points
- Vector3f CalculateSphereCenter(const Vector3f& p1, const Vector3f& p2,
- const Vector3f& p3, const Vector3f& p4);
-
- // Distance from p4 to the nearest point on a plane through p1, p2, p3
- float PointToPlaneDistance(const Vector3f& p1, const Vector3f& p2,
- const Vector3f& p3, const Vector3f& p4);
-
- Vector3f MagCenter;
- unsigned Status;
- float MinMagDistance;
- float MinQuatDistance;
- float MinMagDistanceSq;
- float MinQuatDistanceSq;
-
- unsigned SampleCount;
- Vector3f MagSamples[4];
- Quatf QuatSamples[4];
-
-};
-
-}}
-
-#endif
+/************************************************************************************
+
+PublicHeader: OVR.h
+Filename : Util_MagCalibration.h
+Content : Procedures for calibrating the magnetometer
+Created : April 16, 2013
+Authors : Steve LaValle, Andrew Reisse
+
+Copyright : Copyright 2013 Oculus VR, Inc. All Rights reserved.
+
+Use of this software is subject to the terms of the Oculus license
+agreement provided at the time of installation or download, or which
+otherwise accompanies this software in either electronic or hard copy form.
+
+*************************************************************************************/
+
+#ifndef OVR_Util_MagCalibration_h
+#define OVR_Util_MagCalibration_h
+
+#include "../OVR_SensorFusion.h"
+#include "../Kernel/OVR_String.h"
+#include "../Kernel/OVR_Log.h"
+
+namespace OVR { namespace Util {
+
+class MagCalibration
+{
+public:
+ enum MagStatus
+ {
+ Mag_Uninitialized = 0,
+ Mag_AutoCalibrating = 1,
+ Mag_ManuallyCalibrating = 2,
+ Mag_Calibrated = 3
+ };
+
+ MagCalibration() :
+ Stat(Mag_Uninitialized),
+ MinMagDistance(0.2f), MinQuatDistance(0.5f),
+ SampleCount(0)
+ {
+ MinMagDistanceSq = MinMagDistance * MinMagDistance;
+ MinQuatDistanceSq = MinQuatDistance * MinQuatDistance;
+ }
+
+ // Methods that are useful for either auto or manual calibration
+ bool IsUnitialized() const { return Stat == Mag_Uninitialized; }
+ bool IsCalibrated() const { return Stat == Mag_Calibrated; }
+ int NumberOfSamples() const { return SampleCount; }
+ int RequiredSampleCount() const { return 4; }
+ void AbortCalibration()
+ {
+ Stat = Mag_Uninitialized;
+ SampleCount = 0;
+ }
+
+ void ClearCalibration(SensorFusion& sf)
+ {
+ Stat = Mag_Uninitialized;
+ SampleCount = 0;
+ sf.ClearMagCalibration();
+ };
+
+ // Methods for automatic magnetometer calibration
+ void BeginAutoCalibration(SensorFusion& sf);
+ unsigned UpdateAutoCalibration(SensorFusion& sf);
+ bool IsAutoCalibrating() const { return Stat == Mag_AutoCalibrating; }
+
+ // Methods for building a manual (user-guided) calibraton procedure
+ void BeginManualCalibration(SensorFusion& sf);
+ bool IsAcceptableSample(const Quatf& q, const Vector3f& m);
+ bool InsertIfAcceptable(const Quatf& q, const Vector3f& m);
+ // Returns true if successful, requiring that SampleCount = 4
+ bool SetCalibration(SensorFusion& sf);
+ bool IsManuallyCalibrating() const { return Stat == Mag_ManuallyCalibrating; }
+
+ // This is the minimum acceptable distance (Euclidean) between raw
+ // magnetometer values to be acceptable for usage in calibration.
+ void SetMinMagDistance(float dist)
+ {
+ MinMagDistance = dist;
+ MinMagDistanceSq = MinMagDistance * MinMagDistance;
+ }
+
+ // The minimum acceptable distance (4D Euclidean) between orientations
+ // to be acceptable for calibration usage.
+ void SetMinQuatDistance(float dist)
+ {
+ MinQuatDistance = dist;
+ MinQuatDistanceSq = MinQuatDistance * MinQuatDistance;
+ }
+
+ // A result of the calibration, which is the center of a sphere that
+ // roughly approximates the magnetometer data.
+ Vector3f GetMagCenter() const { return MagCenter; }
+
+private:
+ // Determine the unique sphere through 4 non-coplanar points
+ Vector3f CalculateSphereCenter(const Vector3f& p1, const Vector3f& p2,
+ const Vector3f& p3, const Vector3f& p4);
+
+ // Distance from p4 to the nearest point on a plane through p1, p2, p3
+ float PointToPlaneDistance(const Vector3f& p1, const Vector3f& p2,
+ const Vector3f& p3, const Vector3f& p4);
+
+ Vector3f MagCenter;
+ unsigned Stat;
+ float MinMagDistance;
+ float MinQuatDistance;
+ float MinMagDistanceSq;
+ float MinQuatDistanceSq;
+
+ unsigned SampleCount;
+ Vector3f MagSamples[4];
+ Quatf QuatSamples[4];
+
+};
+
+}}
+
+#endif
diff --git a/LibOVR/Src/Util/Util_Render_Stereo.cpp b/LibOVR/Src/Util/Util_Render_Stereo.cpp
index 8986e30..b16cfb5 100644
--- a/LibOVR/Src/Util/Util_Render_Stereo.cpp
+++ b/LibOVR/Src/Util/Util_Render_Stereo.cpp
@@ -1,311 +1,314 @@
-/************************************************************************************
-
-Filename : Util_Render_Stereo.cpp
-Content : Stereo rendering configuration implementation
-Created : October 22, 2012
-Authors : Michael Antonov, Andrew Reisse
-
-Copyright : Copyright 2012 Oculus, Inc. All Rights reserved.
-
-Use of this software is subject to the terms of the Oculus Inc license
-agreement provided at the time of installation or download, or which
-otherwise accompanies this software in either electronic or hard copy form.
-
-*************************************************************************************/
-
-#include "Util_Render_Stereo.h"
-
-namespace OVR { namespace Util { namespace Render {
-
-
-//-----------------------------------------------------------------------------------
-
-// DistortionFnInverse computes the inverse of the distortion function on an argument.
-float DistortionConfig::DistortionFnInverse(float r)
-{
- OVR_ASSERT((r <= 10.0f));
-
- float s, d;
- float delta = r * 0.25f;
-
- s = r * 0.5f;
- d = fabs(r - DistortionFn(s));
-
- for (int i = 0; i < 20; i++)
- {
- float sUp = s + delta;
- float sDown = s - delta;
- float dUp = fabs(r - DistortionFn(sUp));
- float dDown = fabs(r - DistortionFn(sDown));
-
- if (dUp < d)
- {
- s = sUp;
- d = dUp;
- }
- else if (dDown < d)
- {
- s = sDown;
- d = dDown;
- }
- else
- {
- delta *= 0.5f;
- }
- }
-
- return s;
-}
-
-
-//-----------------------------------------------------------------------------------
-// **** StereoConfig Implementation
-
-StereoConfig::StereoConfig(StereoMode mode, const Viewport& vp)
- : Mode(mode),
- InterpupillaryDistance(0.064f), AspectMultiplier(1.0f),
- FullView(vp), DirtyFlag(true),
- YFov(0), Aspect(vp.w / float(vp.h)), ProjectionCenterOffset(0),
- OrthoPixelOffset(0)
-{
- // And default distortion for it.
- Distortion.SetCoefficients(1.0f, 0.22f, 0.24f);
- Distortion.Scale = 1.0f; // Will be computed later.
-
- // Fit left of the image.
- DistortionFitX = -1.0f;
- DistortionFitY = 0.0f;
-
- // Initialize "fake" default HMD values for testing without HMD plugged in.
- // These default values match those returned by the HMD.
- HMD.HResolution = 1280;
- HMD.VResolution = 800;
- HMD.HScreenSize = 0.14976f;
- HMD.VScreenSize = HMD.HScreenSize / (1280.0f / 800.0f);
- HMD.InterpupillaryDistance = InterpupillaryDistance;
- HMD.LensSeparationDistance = 0.0635f;
- HMD.EyeToScreenDistance = 0.041f;
- HMD.DistortionK[0] = Distortion.K[0];
- HMD.DistortionK[1] = Distortion.K[1];
- HMD.DistortionK[2] = Distortion.K[2];
- HMD.DistortionK[3] = 0;
-
- Set2DAreaFov(DegreeToRad(85.0f));
-}
-
-void StereoConfig::SetFullViewport(const Viewport& vp)
-{
- if (vp != FullView)
- {
- FullView = vp;
- DirtyFlag = true;
- }
-}
-
-void StereoConfig::SetHMDInfo(const HMDInfo& hmd)
-{
- HMD = hmd;
- Distortion.K[0] = hmd.DistortionK[0];
- Distortion.K[1] = hmd.DistortionK[1];
- Distortion.K[2] = hmd.DistortionK[2];
- Distortion.K[3] = hmd.DistortionK[3];
-
- Distortion.SetChromaticAberration(hmd.ChromaAbCorrection[0], hmd.ChromaAbCorrection[1],
- hmd.ChromaAbCorrection[2], hmd.ChromaAbCorrection[3]);
-
- DirtyFlag = true;
-}
-
-void StereoConfig::SetDistortionFitPointVP(float x, float y)
-{
- DistortionFitX = x;
- DistortionFitY = y;
- DirtyFlag = true;
-}
-
-void StereoConfig::SetDistortionFitPointPixels(float x, float y)
-{
- DistortionFitX = (4 * x / float(FullView.w)) - 1.0f;
- DistortionFitY = (2 * y / float(FullView.h)) - 1.0f;
- DirtyFlag = true;
-}
-
-void StereoConfig::Set2DAreaFov(float fovRadians)
-{
- Area2DFov = fovRadians;
- DirtyFlag = true;
-}
-
-
-const StereoEyeParams& StereoConfig::GetEyeRenderParams(StereoEye eye)
-{
- static const UByte eyeParamIndices[3] = { 0, 0, 1 };
-
- updateIfDirty();
- OVR_ASSERT(eye < sizeof(eyeParamIndices));
- return EyeRenderParams[eyeParamIndices[eye]];
-}
-
-
-void StereoConfig::updateComputedState()
-{
- // Need to compute all of the following:
- // - Aspect Ratio
- // - FOV
- // - Projection offsets for 3D
- // - Distortion XCenterOffset
- // - Update 2D
- // - Initialize EyeRenderParams
-
- // Compute aspect ratio. Stereo mode cuts width in half.
- Aspect = float(FullView.w) / float(FullView.h);
- Aspect *= (Mode == Stereo_None) ? 1.0f : 0.5f;
- Aspect *= AspectMultiplier;
-
- updateDistortionOffsetAndScale();
-
- // Compute Vertical FOV based on distance, distortion, etc.
- // Distance from vertical center to render vertical edge perceived through the lens.
- // This will be larger then normal screen size due to magnification & distortion.
- //
- // This percievedHalfRTDistance equation should hold as long as the render target
- // and display have the same aspect ratios. What we'd like to know is where the edge
- // of the render target will on the perceived screen surface. With NO LENS,
- // the answer would be:
- //
- // halfRTDistance = (VScreenSize / 2) * aspect *
- // DistortionFn_Inverse( DistortionScale / aspect )
- //
- // To model the optical lens we eliminates DistortionFn_Inverse. Aspect ratios
- // cancel out, so we get:
- //
- // halfRTDistance = (VScreenSize / 2) * DistortionScale
- //
- if (Mode == Stereo_None)
- {
- YFov = DegreeToRad(80.0f);
- }
- else
- {
- float percievedHalfRTDistance = (HMD.VScreenSize / 2) * Distortion.Scale;
- YFov = 2.0f * atan(percievedHalfRTDistance/HMD.EyeToScreenDistance);
- }
-
- updateProjectionOffset();
- update2D();
- updateEyeParams();
-
- DirtyFlag = false;
-}
-
-void StereoConfig::updateDistortionOffsetAndScale()
-{
- // Distortion center shift is stored separately, since it isn't affected
- // by the eye distance.
- float lensOffset = HMD.LensSeparationDistance * 0.5f;
- float lensShift = HMD.HScreenSize * 0.25f - lensOffset;
- float lensViewportShift = 4.0f * lensShift / HMD.HScreenSize;
- Distortion.XCenterOffset= lensViewportShift;
-
- // Compute distortion scale from DistortionFitX & DistortionFitY.
- // Fit value of 0.0 means "no fit".
- if ((fabs(DistortionFitX) < 0.0001f) && (fabs(DistortionFitY) < 0.0001f))
- {
- Distortion.Scale = 1.0f;
- }
- else
- {
- // Convert fit value to distortion-centered coordinates before fit radius
- // calculation.
- float stereoAspect = 0.5f * float(FullView.w) / float(FullView.h);
- float dx = DistortionFitX - Distortion.XCenterOffset;
- float dy = DistortionFitY / stereoAspect;
- float fitRadius = sqrt(dx * dx + dy * dy);
- Distortion.Scale = Distortion.DistortionFn(fitRadius)/fitRadius;
- }
-}
-
-void StereoConfig::updateProjectionOffset()
-{
- // Post-projection viewport coordinates range from (-1.0, 1.0), with the
- // center of the left viewport falling at (1/4) of horizontal screen size.
- // We need to shift this projection center to match with the lens center;
- // note that we don't use the IPD here due to collimated light property of the lens.
- // We compute this shift in physical units (meters) to
- // correct for different screen sizes and then rescale to viewport coordinates.
- float viewCenter = HMD.HScreenSize * 0.25f;
- float eyeProjectionShift = viewCenter - HMD.LensSeparationDistance*0.5f;
- ProjectionCenterOffset = 4.0f * eyeProjectionShift / HMD.HScreenSize;
-}
-
-void StereoConfig::update2D()
-{
- // Orthographic projection fakes a screen at a distance of 0.8m from the
- // 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.
- float metersToPixels = (HMD.HResolution / HMD.HScreenSize);
- float lensDistanceScreenPixels= metersToPixels * HMD.LensSeparationDistance;
- float eyeDistanceScreenPixels = metersToPixels * InterpupillaryDistance;
- float offCenterShiftPixels = (HMD.EyeToScreenDistance / 0.8f) * eyeDistanceScreenPixels;
- float leftPixelCenter = (HMD.HResolution / 2) - lensDistanceScreenPixels * 0.5f;
- float rightPixelCenter = lensDistanceScreenPixels * 0.5f;
- float pixelDifference = leftPixelCenter - rightPixelCenter;
-
- // This computes the number of pixels that fit within specified 2D FOV (assuming
- // distortion scaling will be done).
- float percievedHalfScreenDistance = tan(Area2DFov * 0.5f) * HMD.EyeToScreenDistance;
- float vfovSize = 2.0f * percievedHalfScreenDistance / Distortion.Scale;
- FovPixels = HMD.VResolution * vfovSize / HMD.VScreenSize;
-
- // Create orthographic matrix.
- Matrix4f& m = OrthoCenter;
- m.SetIdentity();
- m.M[0][0] = FovPixels / (FullView.w * 0.5f);
- m.M[1][1] = -FovPixels / FullView.h;
- m.M[0][3] = 0;
- m.M[1][3] = 0;
- m.M[2][2] = 0;
-
- float orthoPixelOffset = (pixelDifference + offCenterShiftPixels/Distortion.Scale) * 0.5f;
- OrthoPixelOffset = orthoPixelOffset * 2.0f / FovPixels;
-}
-
-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);
-
- switch(Mode)
- {
- case Stereo_None:
- {
- EyeRenderParams[0].Init(StereoEye_Center, FullView, 0, projCenter, OrthoCenter);
- }
- break;
-
- case Stereo_LeftRight_Multipass:
- {
- Matrix4f projLeft = Matrix4f::Translation(ProjectionCenterOffset, 0, 0) * projCenter,
- projRight = Matrix4f::Translation(-ProjectionCenterOffset, 0, 0) * projCenter;
-
- EyeRenderParams[0].Init(StereoEye_Left,
- Viewport(FullView.x, FullView.y, FullView.w/2, FullView.h),
- +InterpupillaryDistance * 0.5f, // World view shift.
- projLeft, OrthoCenter * Matrix4f::Translation(OrthoPixelOffset, 0, 0),
- &Distortion);
- EyeRenderParams[1].Init(StereoEye_Right,
- Viewport(FullView.x + FullView.w/2, FullView.y, FullView.w/2, FullView.h),
- -InterpupillaryDistance * 0.5f,
- projRight, OrthoCenter * Matrix4f::Translation(-OrthoPixelOffset, 0, 0),
- &Distortion);
- }
- break;
- }
-
-}
-
-
-}}} // OVR::Util::Render
-
+/************************************************************************************
+
+Filename : Util_Render_Stereo.cpp
+Content : Stereo rendering configuration implementation
+Created : October 22, 2012
+Authors : Michael Antonov, Andrew Reisse
+
+Copyright : Copyright 2012 Oculus, Inc. All Rights reserved.
+
+Use of this software is subject to the terms of the Oculus Inc license
+agreement provided at the time of installation or download, or which
+otherwise accompanies this software in either electronic or hard copy form.
+
+*************************************************************************************/
+
+#include "Util_Render_Stereo.h"
+
+namespace OVR { namespace Util { namespace Render {
+
+
+//-----------------------------------------------------------------------------------
+
+// DistortionFnInverse computes the inverse of the distortion function on an argument.
+float DistortionConfig::DistortionFnInverse(float r)
+{
+ OVR_ASSERT((r <= 10.0f));
+
+ float s, d;
+ float delta = r * 0.25f;
+
+ s = r * 0.5f;
+ d = fabs(r - DistortionFn(s));
+
+ for (int i = 0; i < 20; i++)
+ {
+ float sUp = s + delta;
+ float sDown = s - delta;
+ float dUp = fabs(r - DistortionFn(sUp));
+ float dDown = fabs(r - DistortionFn(sDown));
+
+ if (dUp < d)
+ {
+ s = sUp;
+ d = dUp;
+ }
+ else if (dDown < d)
+ {
+ s = sDown;
+ d = dDown;
+ }
+ else
+ {
+ delta *= 0.5f;
+ }
+ }
+
+ return s;
+}
+
+
+//-----------------------------------------------------------------------------------
+// **** StereoConfig Implementation
+
+StereoConfig::StereoConfig(StereoMode mode, const Viewport& vp)
+ : Mode(mode),
+ InterpupillaryDistance(0.064f), AspectMultiplier(1.0f),
+ FullView(vp), DirtyFlag(true), IPDOverride(false),
+ YFov(0), Aspect(vp.w / float(vp.h)), ProjectionCenterOffset(0),
+ OrthoPixelOffset(0)
+{
+ // And default distortion for it.
+ Distortion.SetCoefficients(1.0f, 0.22f, 0.24f);
+ Distortion.Scale = 1.0f; // Will be computed later.
+
+ // Fit left of the image.
+ DistortionFitX = -1.0f;
+ DistortionFitY = 0.0f;
+
+ // Initialize "fake" default HMD values for testing without HMD plugged in.
+ // These default values match those returned by the HMD.
+ HMD.HResolution = 1280;
+ HMD.VResolution = 800;
+ HMD.HScreenSize = 0.14976f;
+ HMD.VScreenSize = HMD.HScreenSize / (1280.0f / 800.0f);
+ HMD.InterpupillaryDistance = InterpupillaryDistance;
+ HMD.LensSeparationDistance = 0.0635f;
+ HMD.EyeToScreenDistance = 0.041f;
+ HMD.DistortionK[0] = Distortion.K[0];
+ HMD.DistortionK[1] = Distortion.K[1];
+ HMD.DistortionK[2] = Distortion.K[2];
+ HMD.DistortionK[3] = 0;
+
+ Set2DAreaFov(DegreeToRad(85.0f));
+}
+
+void StereoConfig::SetFullViewport(const Viewport& vp)
+{
+ if (vp != FullView)
+ {
+ FullView = vp;
+ DirtyFlag = true;
+ }
+}
+
+void StereoConfig::SetHMDInfo(const HMDInfo& hmd)
+{
+ HMD = hmd;
+ Distortion.K[0] = hmd.DistortionK[0];
+ Distortion.K[1] = hmd.DistortionK[1];
+ Distortion.K[2] = hmd.DistortionK[2];
+ Distortion.K[3] = hmd.DistortionK[3];
+
+ Distortion.SetChromaticAberration(hmd.ChromaAbCorrection[0], hmd.ChromaAbCorrection[1],
+ hmd.ChromaAbCorrection[2], hmd.ChromaAbCorrection[3]);
+
+ if (!IPDOverride)
+ InterpupillaryDistance = HMD.InterpupillaryDistance;
+
+ DirtyFlag = true;
+}
+
+void StereoConfig::SetDistortionFitPointVP(float x, float y)
+{
+ DistortionFitX = x;
+ DistortionFitY = y;
+ DirtyFlag = true;
+}
+
+void StereoConfig::SetDistortionFitPointPixels(float x, float y)
+{
+ DistortionFitX = (4 * x / float(FullView.w)) - 1.0f;
+ DistortionFitY = (2 * y / float(FullView.h)) - 1.0f;
+ DirtyFlag = true;
+}
+
+void StereoConfig::Set2DAreaFov(float fovRadians)
+{
+ Area2DFov = fovRadians;
+ DirtyFlag = true;
+}
+
+
+const StereoEyeParams& StereoConfig::GetEyeRenderParams(StereoEye eye)
+{
+ static const UByte eyeParamIndices[3] = { 0, 0, 1 };
+
+ updateIfDirty();
+ OVR_ASSERT(eye < sizeof(eyeParamIndices));
+ return EyeRenderParams[eyeParamIndices[eye]];
+}
+
+
+void StereoConfig::updateComputedState()
+{
+ // Need to compute all of the following:
+ // - Aspect Ratio
+ // - FOV
+ // - Projection offsets for 3D
+ // - Distortion XCenterOffset
+ // - Update 2D
+ // - Initialize EyeRenderParams
+
+ // Compute aspect ratio. Stereo mode cuts width in half.
+ Aspect = float(FullView.w) / float(FullView.h);
+ Aspect *= (Mode == Stereo_None) ? 1.0f : 0.5f;
+ Aspect *= AspectMultiplier;
+
+ updateDistortionOffsetAndScale();
+
+ // Compute Vertical FOV based on distance, distortion, etc.
+ // Distance from vertical center to render vertical edge perceived through the lens.
+ // This will be larger then normal screen size due to magnification & distortion.
+ //
+ // This percievedHalfRTDistance equation should hold as long as the render target
+ // and display have the same aspect ratios. What we'd like to know is where the edge
+ // of the render target will on the perceived screen surface. With NO LENS,
+ // the answer would be:
+ //
+ // halfRTDistance = (VScreenSize / 2) * aspect *
+ // DistortionFn_Inverse( DistortionScale / aspect )
+ //
+ // To model the optical lens we eliminates DistortionFn_Inverse. Aspect ratios
+ // cancel out, so we get:
+ //
+ // halfRTDistance = (VScreenSize / 2) * DistortionScale
+ //
+ if (Mode == Stereo_None)
+ {
+ YFov = DegreeToRad(80.0f);
+ }
+ else
+ {
+ float percievedHalfRTDistance = (HMD.VScreenSize / 2) * Distortion.Scale;
+ YFov = 2.0f * atan(percievedHalfRTDistance/HMD.EyeToScreenDistance);
+ }
+
+ updateProjectionOffset();
+ update2D();
+ updateEyeParams();
+
+ DirtyFlag = false;
+}
+
+void StereoConfig::updateDistortionOffsetAndScale()
+{
+ // Distortion center shift is stored separately, since it isn't affected
+ // by the eye distance.
+ float lensOffset = HMD.LensSeparationDistance * 0.5f;
+ float lensShift = HMD.HScreenSize * 0.25f - lensOffset;
+ float lensViewportShift = 4.0f * lensShift / HMD.HScreenSize;
+ Distortion.XCenterOffset= lensViewportShift;
+
+ // Compute distortion scale from DistortionFitX & DistortionFitY.
+ // Fit value of 0.0 means "no fit".
+ if ((fabs(DistortionFitX) < 0.0001f) && (fabs(DistortionFitY) < 0.0001f))
+ {
+ Distortion.Scale = 1.0f;
+ }
+ else
+ {
+ // Convert fit value to distortion-centered coordinates before fit radius
+ // calculation.
+ float stereoAspect = 0.5f * float(FullView.w) / float(FullView.h);
+ float dx = DistortionFitX - Distortion.XCenterOffset;
+ float dy = DistortionFitY / stereoAspect;
+ float fitRadius = sqrt(dx * dx + dy * dy);
+ Distortion.Scale = Distortion.DistortionFn(fitRadius)/fitRadius;
+ }
+}
+
+void StereoConfig::updateProjectionOffset()
+{
+ // Post-projection viewport coordinates range from (-1.0, 1.0), with the
+ // center of the left viewport falling at (1/4) of horizontal screen size.
+ // We need to shift this projection center to match with the lens center;
+ // note that we don't use the IPD here due to collimated light property of the lens.
+ // We compute this shift in physical units (meters) to
+ // correct for different screen sizes and then rescale to viewport coordinates.
+ float viewCenter = HMD.HScreenSize * 0.25f;
+ float eyeProjectionShift = viewCenter - HMD.LensSeparationDistance*0.5f;
+ ProjectionCenterOffset = 4.0f * eyeProjectionShift / HMD.HScreenSize;
+}
+
+void StereoConfig::update2D()
+{
+ // Orthographic projection fakes a screen at a distance of 0.8m from the
+ // 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.
+ float metersToPixels = (HMD.HResolution / HMD.HScreenSize);
+ float lensDistanceScreenPixels= metersToPixels * HMD.LensSeparationDistance;
+ float eyeDistanceScreenPixels = metersToPixels * InterpupillaryDistance;
+ float offCenterShiftPixels = (HMD.EyeToScreenDistance / 0.8f) * eyeDistanceScreenPixels;
+ float leftPixelCenter = (HMD.HResolution / 2) - lensDistanceScreenPixels * 0.5f;
+ float rightPixelCenter = lensDistanceScreenPixels * 0.5f;
+ float pixelDifference = leftPixelCenter - rightPixelCenter;
+
+ // This computes the number of pixels that fit within specified 2D FOV (assuming
+ // distortion scaling will be done).
+ float percievedHalfScreenDistance = tan(Area2DFov * 0.5f) * HMD.EyeToScreenDistance;
+ float vfovSize = 2.0f * percievedHalfScreenDistance / Distortion.Scale;
+ FovPixels = HMD.VResolution * vfovSize / HMD.VScreenSize;
+
+ // Create orthographic matrix.
+ Matrix4f& m = OrthoCenter;
+ m.SetIdentity();
+ m.M[0][0] = FovPixels / (FullView.w * 0.5f);
+ m.M[1][1] = -FovPixels / FullView.h;
+ m.M[0][3] = 0;
+ m.M[1][3] = 0;
+ m.M[2][2] = 0;
+
+ float orthoPixelOffset = (pixelDifference + offCenterShiftPixels/Distortion.Scale) * 0.5f;
+ OrthoPixelOffset = orthoPixelOffset * 2.0f / FovPixels;
+}
+
+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);
+
+ switch(Mode)
+ {
+ case Stereo_None:
+ {
+ EyeRenderParams[0].Init(StereoEye_Center, FullView, 0, projCenter, OrthoCenter);
+ }
+ break;
+
+ case Stereo_LeftRight_Multipass:
+ {
+ Matrix4f projLeft = Matrix4f::Translation(ProjectionCenterOffset, 0, 0) * projCenter,
+ projRight = Matrix4f::Translation(-ProjectionCenterOffset, 0, 0) * projCenter;
+
+ EyeRenderParams[0].Init(StereoEye_Left,
+ Viewport(FullView.x, FullView.y, FullView.w/2, FullView.h),
+ +InterpupillaryDistance * 0.5f, // World view shift.
+ projLeft, OrthoCenter * Matrix4f::Translation(OrthoPixelOffset, 0, 0),
+ &Distortion);
+ EyeRenderParams[1].Init(StereoEye_Right,
+ Viewport(FullView.x + FullView.w/2, FullView.y, FullView.w/2, FullView.h),
+ -InterpupillaryDistance * 0.5f,
+ projRight, OrthoCenter * Matrix4f::Translation(-OrthoPixelOffset, 0, 0),
+ &Distortion);
+ }
+ break;
+ }
+
+}
+
+
+}}} // OVR::Util::Render
+
diff --git a/LibOVR/Src/Util/Util_Render_Stereo.h b/LibOVR/Src/Util/Util_Render_Stereo.h
index 9dc110c..9ac4002 100644
--- a/LibOVR/Src/Util/Util_Render_Stereo.h
+++ b/LibOVR/Src/Util/Util_Render_Stereo.h
@@ -1,299 +1,300 @@
-/************************************************************************************
-
-PublicHeader: OVR.h
-Filename : Util_Render_Stereo.h
-Content : Sample stereo rendering configuration classes.
-Created : October 22, 2012
-Authors : Michael Antonov
-
-Copyright : Copyright 2012 Oculus, Inc. All Rights reserved.
-
-Use of this software is subject to the terms of the Oculus Inc license
-agreement provided at the time of installation or download, or which
-otherwise accompanies this software in either electronic or hard copy form.
-
-*************************************************************************************/
-
-#ifndef OVR_Util_Render_Stereo_h
-#define OVR_Util_Render_Stereo_h
-
-#include "../OVR_Device.h"
-
-namespace OVR { namespace Util { namespace Render {
-
-
-//-----------------------------------------------------------------------------------
-// ***** Stereo Enumerations
-
-// StereoMode describes rendering modes that can be used by StereoConfig.
-// These modes control whether stereo rendering is used or not (Stereo_None),
-// and how it is implemented.
-enum StereoMode
-{
- Stereo_None = 0,
- Stereo_LeftRight_Multipass = 1
-};
-
-
-// StereoEye specifies which eye we are rendering for; it is used to
-// retrieve StereoEyeParams.
-enum StereoEye
-{
- StereoEye_Center,
- StereoEye_Left,
- StereoEye_Right
-};
-
-
-//-----------------------------------------------------------------------------------
-// ***** Viewport
-
-// Viewport describes a rectangular area used for rendering, in pixels.
-struct Viewport
-{
- int x, y;
- int w, h;
-
- Viewport() {}
- Viewport(int x1, int y1, int w1, int h1) : x(x1), y(y1), w(w1), h(h1) { }
-
- bool operator == (const Viewport& vp) const
- { return (x == vp.x) && (y == vp.y) && (w == vp.w) && (h == vp.h); }
- bool operator != (const Viewport& vp) const
- { return !operator == (vp); }
-};
-
-
-//-----------------------------------------------------------------------------------
-// ***** DistortionConfig
-
-// DistortionConfig Provides controls for the distortion shader.
-// - K[0] - K[3] are coefficients for the distortion function.
-// - XCenterOffset is the offset of lens distortion center from the
-// center of one-eye screen half. [-1, 1] Range.
-// - Scale is a factor of how much larger will the input image be,
-// with a factor of 1.0f being no scaling. An inverse of this
-// value is applied to sampled UV coordinates (1/Scale).
-// - ChromaticAberration is an array of parameters for controlling
-// additional Red and Blue scaling in order to reduce chromatic aberration
-// caused by the Rift lenses.
-class DistortionConfig
-{
-public:
- DistortionConfig(float k0 = 1.0f, float k1 = 0.0f, float k2 = 0.0f, float k3 = 0.0f)
- : XCenterOffset(0), YCenterOffset(0), Scale(1.0f)
- {
- SetCoefficients(k0, k1, k2, k3);
- SetChromaticAberration();
- }
-
- void SetCoefficients(float k0, float k1 = 0.0f, float k2 = 0.0f, float k3 = 0.0f)
- { K[0] = k0; K[1] = k1; K[2] = k2; K[3] = k3; }
-
- void SetChromaticAberration(float red1 = 1.0f, float red2 = 0.0f, float blue1 = 1.0f, float blue2 = 0.0f)
- { ChromaticAberration[0] = red1; ChromaticAberration[1] = red2; ChromaticAberration[2] = blue1; ChromaticAberration[3] = blue2; }
-
-
- // DistortionFn applies distortion equation to the argument. The returned
- // value should match distortion equation used in shader.
- float DistortionFn(float r) const
- {
- float rsq = r * r;
- float scale = r * (K[0] + K[1] * rsq + K[2] * rsq * rsq + K[3] * rsq * rsq * rsq);
- return scale;
- }
-
- // DistortionFnInverse computes the inverse of the distortion function on an argument.
- float DistortionFnInverse(float r);
-
- float K[4];
- float XCenterOffset, YCenterOffset;
- float Scale;
-
- float ChromaticAberration[4]; // Additional per-channel scaling is applied after distortion:
- // Index [0] - Red channel constant coefficient.
- // Index [1] - Red channel r^2 coefficient.
- // Index [2] - Blue channel constant coefficient.
- // Index [3] - Blue channel r^2 coefficient.
-};
-
-
-//-----------------------------------------------------------------------------------
-// ***** StereoEyeParams
-
-// StereoEyeParams describes RenderDevice configuration needed to render
-// the scene for one eye.
-class StereoEyeParams
-{
-public:
- StereoEye Eye;
- Viewport VP; // Viewport that we are rendering to
- const DistortionConfig* pDistortion;
-
- Matrix4f ViewAdjust; // Translation to be applied to view matrix.
- Matrix4f Projection; // Projection matrix used with this eye.
- Matrix4f OrthoProjection; // Orthographic projection used with this eye.
-
- void Init(StereoEye eye, const Viewport &vp, float vofs,
- const Matrix4f& proj, const Matrix4f& orthoProj,
- const DistortionConfig* distortion = 0)
- {
- Eye = eye;
- VP = vp;
- ViewAdjust = Matrix4f::Translation(Vector3f(vofs,0,0));
- Projection = proj;
- OrthoProjection = orthoProj;
- pDistortion = distortion;
- }
-};
-
-
-//-----------------------------------------------------------------------------------
-// ***** StereoConfig
-
-// StereoConfig maintains a scene stereo state and allow switching between different
-// stereo rendering modes. To support rendering, StereoConfig keeps track of HMD
-// variables such as screen size, eye-to-screen distance and distortion, and computes
-// extra data such as FOV and distortion center offsets based on it. Rendering
-// parameters are returned though StereoEyeParams for each eye.
-//
-// Beyond regular 3D projection, this class supports rendering a 2D orthographic
-// surface for UI and text. The 2D surface will be defined as fitting within a 2D
-// field of view (85 degrees by default) and used [-1,1] coordinate system with
-// square pixels. The (0,0) coordinate corresponds to eye center location
-// that is properly adjusted during rendering through SterepRenderParams::Adjust2D.
-// Genreally speaking, text outside [-1,1] coordinate range will not be readable.
-
-class StereoConfig
-{
-public:
-
- StereoConfig(StereoMode mode = Stereo_LeftRight_Multipass,
- const Viewport& fullViewport = Viewport(0,0, 1280,800));
-
-
- // *** Modifiable State Access
-
- // Sets a stereo rendering mode and updates internal cached
- // state (matrices, per-eye view) based on it.
- void SetStereoMode(StereoMode mode) { Mode = mode; DirtyFlag = true; }
- StereoMode GetStereoMode() const { return Mode; }
-
- // Sets HMD parameters; also initializes distortion coefficients.
- void SetHMDInfo(const HMDInfo& hmd);
- const HMDInfo& GetHMDInfo() const { return HMD; }
-
- // Query physical eye-to-screen distance in meters, which combines screen-to-lens and
- // and lens-to-eye pupil distances. Modifying this value adjusts FOV.
- float GetEyeToScreenDistance() const { return HMD.EyeToScreenDistance; }
- void SetEyeToScreenDistance(float esd) { HMD.EyeToScreenDistance = esd; DirtyFlag = true; }
-
- // Interpupillary distance used for stereo, in meters. Default is 0.064m (64 mm).
- void SetIPD(float ipd) { InterpupillaryDistance = ipd; DirtyFlag = true; }
- float GetIPD() const { return InterpupillaryDistance; }
-
- // Set full render target viewport; for HMD this includes both eyes.
- void SetFullViewport(const Viewport& vp);
- const Viewport& GetFullViewport() const { return FullView; }
-
- // Aspect ratio defaults to ((w/h)*multiplier) computed per eye.
- // Aspect multiplier allows adjusting aspect ratio consistently for Stereo/NoStereo.
- void SetAspectMultiplier(float m) { AspectMultiplier = m; DirtyFlag = true; }
- float GetAspectMultiplier() const { return AspectMultiplier; }
-
-
- // For the distorted image to fill rendered viewport, input texture render target needs to be
- // scaled by DistortionScale before sampling. The scale factor is computed by fitting a point
- // on of specified radius from a distortion center, more easily specified as a coordinate.
- // SetDistortionFitPointVP sets the (x,y) coordinate of the point that scale will be "fit" to,
- // assuming [-1,1] coordinate range for full left-eye viewport. A fit point is a location
- // where source (pre-distortion) and target (post-distortion) image match each other.
- // For the right eye, the interpretation of 'u' will be inverted.
- void SetDistortionFitPointVP(float x, float y);
- // SetDistortionFitPointPixels sets the (x,y) coordinate of the point that scale will be "fit" to,
- // specified in pixeld for full left-eye texture.
- void SetDistortionFitPointPixels(float x, float y);
-
- // Changes all distortion settings.
- // Note that setting HMDInfo also changes Distortion coefficients.
- void SetDistortionConfig(const DistortionConfig& d) { Distortion = d; DirtyFlag = true; }
-
- // Modify distortion coefficients; useful for adjustment tweaking.
- void SetDistortionK(int i, float k) { Distortion.K[i] = k; DirtyFlag = true; }
- float GetDistortionK(int i) const { return Distortion.K[i]; }
-
- // Sets the fieldOfView that the 2D coordinate area stretches to.
- void Set2DAreaFov(float fovRadians);
-
-
- // *** Computed State
-
- // Return current aspect ratio.
- float GetAspect() { updateIfDirty(); return Aspect; }
-
- // Return computed vertical FOV in radians/degrees.
- float GetYFOVRadians() { updateIfDirty(); return YFov; }
- float GetYFOVDegrees() { return RadToDegree(GetYFOVRadians()); }
-
- // Query horizontal projection center offset as a distance away from the
- // one-eye [-1,1] unit viewport.
- // Positive return value should be used for left eye, negative for right eye.
- float GetProjectionCenterOffset() { updateIfDirty(); return ProjectionCenterOffset; }
-
- // GetDistortionConfig isn't const because XCenterOffset bay need to be recomputed.
- const DistortionConfig& GetDistortionConfig() { updateIfDirty(); return Distortion; }
-
- // Returns DistortionScale factor by which input texture size is increased to make
- // post-distortion result distortion fit the viewport.
- float GetDistortionScale() { updateIfDirty(); return Distortion.Scale; }
-
- // Returns the size of a pixel within 2D coordinate system.
- float Get2DUnitPixel() { updateIfDirty(); return (2.0f / (FovPixels * Distortion.Scale)); }
-
- // Returns full set of Stereo rendering parameters for the specified eye.
- const StereoEyeParams& GetEyeRenderParams(StereoEye eye);
-
-private:
-
- void updateIfDirty() { if (DirtyFlag) updateComputedState(); }
- void updateComputedState();
-
- void updateDistortionOffsetAndScale();
- void updateProjectionOffset();
- void update2D();
- void updateEyeParams();
-
-
- // *** Modifiable State
-
- StereoMode Mode;
- float InterpupillaryDistance;
- float AspectMultiplier; // Multiplied into aspect ratio to change it.
- HMDInfo HMD;
- DistortionConfig Distortion;
- float DistortionFitX, DistortionFitY; // In [-1,1] half-screen viewport units.
- Viewport FullView; // Entire window viewport.
-
- float Area2DFov; // FOV range mapping to [-1, 1] 2D area.
-
- // *** Computed State
-
- bool DirtyFlag; // Set when any if the modifiable state changed.
- float YFov; // Vertical FOV.
- float Aspect; // Aspect ratio: (w/h)*AspectMultiplier.
- float ProjectionCenterOffset;
- StereoEyeParams EyeRenderParams[2];
-
-
- // ** 2D Rendering
-
- // Number of 2D pixels in the FOV. This defines [-1,1] coordinate range for 2D.
- float FovPixels;
- Matrix4f OrthoCenter;
- float OrthoPixelOffset;
-};
-
-
-}}} // OVR::Util::Render
-
-#endif
+/************************************************************************************
+
+PublicHeader: OVR.h
+Filename : Util_Render_Stereo.h
+Content : Sample stereo rendering configuration classes.
+Created : October 22, 2012
+Authors : Michael Antonov
+
+Copyright : Copyright 2012 Oculus, Inc. All Rights reserved.
+
+Use of this software is subject to the terms of the Oculus Inc license
+agreement provided at the time of installation or download, or which
+otherwise accompanies this software in either electronic or hard copy form.
+
+*************************************************************************************/
+
+#ifndef OVR_Util_Render_Stereo_h
+#define OVR_Util_Render_Stereo_h
+
+#include "../OVR_Device.h"
+
+namespace OVR { namespace Util { namespace Render {
+
+
+//-----------------------------------------------------------------------------------
+// ***** Stereo Enumerations
+
+// StereoMode describes rendering modes that can be used by StereoConfig.
+// These modes control whether stereo rendering is used or not (Stereo_None),
+// and how it is implemented.
+enum StereoMode
+{
+ Stereo_None = 0,
+ Stereo_LeftRight_Multipass = 1
+};
+
+
+// StereoEye specifies which eye we are rendering for; it is used to
+// retrieve StereoEyeParams.
+enum StereoEye
+{
+ StereoEye_Center,
+ StereoEye_Left,
+ StereoEye_Right
+};
+
+
+//-----------------------------------------------------------------------------------
+// ***** Viewport
+
+// Viewport describes a rectangular area used for rendering, in pixels.
+struct Viewport
+{
+ int x, y;
+ int w, h;
+
+ Viewport() {}
+ Viewport(int x1, int y1, int w1, int h1) : x(x1), y(y1), w(w1), h(h1) { }
+
+ bool operator == (const Viewport& vp) const
+ { return (x == vp.x) && (y == vp.y) && (w == vp.w) && (h == vp.h); }
+ bool operator != (const Viewport& vp) const
+ { return !operator == (vp); }
+};
+
+
+//-----------------------------------------------------------------------------------
+// ***** DistortionConfig
+
+// DistortionConfig Provides controls for the distortion shader.
+// - K[0] - K[3] are coefficients for the distortion function.
+// - XCenterOffset is the offset of lens distortion center from the
+// center of one-eye screen half. [-1, 1] Range.
+// - Scale is a factor of how much larger will the input image be,
+// with a factor of 1.0f being no scaling. An inverse of this
+// value is applied to sampled UV coordinates (1/Scale).
+// - ChromaticAberration is an array of parameters for controlling
+// additional Red and Blue scaling in order to reduce chromatic aberration
+// caused by the Rift lenses.
+class DistortionConfig
+{
+public:
+ DistortionConfig(float k0 = 1.0f, float k1 = 0.0f, float k2 = 0.0f, float k3 = 0.0f)
+ : XCenterOffset(0), YCenterOffset(0), Scale(1.0f)
+ {
+ SetCoefficients(k0, k1, k2, k3);
+ SetChromaticAberration();
+ }
+
+ void SetCoefficients(float k0, float k1 = 0.0f, float k2 = 0.0f, float k3 = 0.0f)
+ { K[0] = k0; K[1] = k1; K[2] = k2; K[3] = k3; }
+
+ void SetChromaticAberration(float red1 = 1.0f, float red2 = 0.0f, float blue1 = 1.0f, float blue2 = 0.0f)
+ { ChromaticAberration[0] = red1; ChromaticAberration[1] = red2; ChromaticAberration[2] = blue1; ChromaticAberration[3] = blue2; }
+
+
+ // DistortionFn applies distortion equation to the argument. The returned
+ // value should match distortion equation used in shader.
+ float DistortionFn(float r) const
+ {
+ float rsq = r * r;
+ float scale = r * (K[0] + K[1] * rsq + K[2] * rsq * rsq + K[3] * rsq * rsq * rsq);
+ return scale;
+ }
+
+ // DistortionFnInverse computes the inverse of the distortion function on an argument.
+ float DistortionFnInverse(float r);
+
+ float K[4];
+ float XCenterOffset, YCenterOffset;
+ float Scale;
+
+ float ChromaticAberration[4]; // Additional per-channel scaling is applied after distortion:
+ // Index [0] - Red channel constant coefficient.
+ // Index [1] - Red channel r^2 coefficient.
+ // Index [2] - Blue channel constant coefficient.
+ // Index [3] - Blue channel r^2 coefficient.
+};
+
+
+//-----------------------------------------------------------------------------------
+// ***** StereoEyeParams
+
+// StereoEyeParams describes RenderDevice configuration needed to render
+// the scene for one eye.
+class StereoEyeParams
+{
+public:
+ StereoEye Eye;
+ Viewport VP; // Viewport that we are rendering to
+ const DistortionConfig* pDistortion;
+
+ Matrix4f ViewAdjust; // Translation to be applied to view matrix.
+ Matrix4f Projection; // Projection matrix used with this eye.
+ Matrix4f OrthoProjection; // Orthographic projection used with this eye.
+
+ void Init(StereoEye eye, const Viewport &vp, float vofs,
+ const Matrix4f& proj, const Matrix4f& orthoProj,
+ const DistortionConfig* distortion = 0)
+ {
+ Eye = eye;
+ VP = vp;
+ ViewAdjust = Matrix4f::Translation(Vector3f(vofs,0,0));
+ Projection = proj;
+ OrthoProjection = orthoProj;
+ pDistortion = distortion;
+ }
+};
+
+
+//-----------------------------------------------------------------------------------
+// ***** StereoConfig
+
+// StereoConfig maintains a scene stereo state and allow switching between different
+// stereo rendering modes. To support rendering, StereoConfig keeps track of HMD
+// variables such as screen size, eye-to-screen distance and distortion, and computes
+// extra data such as FOV and distortion center offsets based on it. Rendering
+// parameters are returned though StereoEyeParams for each eye.
+//
+// Beyond regular 3D projection, this class supports rendering a 2D orthographic
+// surface for UI and text. The 2D surface will be defined as fitting within a 2D
+// field of view (85 degrees by default) and used [-1,1] coordinate system with
+// square pixels. The (0,0) coordinate corresponds to eye center location
+// that is properly adjusted during rendering through SterepRenderParams::Adjust2D.
+// Genreally speaking, text outside [-1,1] coordinate range will not be readable.
+
+class StereoConfig
+{
+public:
+
+ StereoConfig(StereoMode mode = Stereo_LeftRight_Multipass,
+ const Viewport& fullViewport = Viewport(0,0, 1280,800));
+
+
+ // *** Modifiable State Access
+
+ // Sets a stereo rendering mode and updates internal cached
+ // state (matrices, per-eye view) based on it.
+ void SetStereoMode(StereoMode mode) { Mode = mode; DirtyFlag = true; }
+ StereoMode GetStereoMode() const { return Mode; }
+
+ // Sets HMD parameters; also initializes distortion coefficients.
+ void SetHMDInfo(const HMDInfo& hmd);
+ const HMDInfo& GetHMDInfo() const { return HMD; }
+
+ // Query physical eye-to-screen distance in meters, which combines screen-to-lens and
+ // and lens-to-eye pupil distances. Modifying this value adjusts FOV.
+ float GetEyeToScreenDistance() const { return HMD.EyeToScreenDistance; }
+ void SetEyeToScreenDistance(float esd) { HMD.EyeToScreenDistance = esd; DirtyFlag = true; }
+
+ // Interpupillary distance used for stereo, in meters. Default is 0.064m (64 mm).
+ void SetIPD(float ipd) { InterpupillaryDistance = ipd; IPDOverride = DirtyFlag = true; }
+ float GetIPD() const { return InterpupillaryDistance; }
+
+ // Set full render target viewport; for HMD this includes both eyes.
+ void SetFullViewport(const Viewport& vp);
+ const Viewport& GetFullViewport() const { return FullView; }
+
+ // Aspect ratio defaults to ((w/h)*multiplier) computed per eye.
+ // Aspect multiplier allows adjusting aspect ratio consistently for Stereo/NoStereo.
+ void SetAspectMultiplier(float m) { AspectMultiplier = m; DirtyFlag = true; }
+ float GetAspectMultiplier() const { return AspectMultiplier; }
+
+
+ // For the distorted image to fill rendered viewport, input texture render target needs to be
+ // scaled by DistortionScale before sampling. The scale factor is computed by fitting a point
+ // on of specified radius from a distortion center, more easily specified as a coordinate.
+ // SetDistortionFitPointVP sets the (x,y) coordinate of the point that scale will be "fit" to,
+ // assuming [-1,1] coordinate range for full left-eye viewport. A fit point is a location
+ // where source (pre-distortion) and target (post-distortion) image match each other.
+ // For the right eye, the interpretation of 'u' will be inverted.
+ void SetDistortionFitPointVP(float x, float y);
+ // SetDistortionFitPointPixels sets the (x,y) coordinate of the point that scale will be "fit" to,
+ // specified in pixeld for full left-eye texture.
+ void SetDistortionFitPointPixels(float x, float y);
+
+ // Changes all distortion settings.
+ // Note that setting HMDInfo also changes Distortion coefficients.
+ void SetDistortionConfig(const DistortionConfig& d) { Distortion = d; DirtyFlag = true; }
+
+ // Modify distortion coefficients; useful for adjustment tweaking.
+ void SetDistortionK(int i, float k) { Distortion.K[i] = k; DirtyFlag = true; }
+ float GetDistortionK(int i) const { return Distortion.K[i]; }
+
+ // Sets the fieldOfView that the 2D coordinate area stretches to.
+ void Set2DAreaFov(float fovRadians);
+
+
+ // *** Computed State
+
+ // Return current aspect ratio.
+ float GetAspect() { updateIfDirty(); return Aspect; }
+
+ // Return computed vertical FOV in radians/degrees.
+ float GetYFOVRadians() { updateIfDirty(); return YFov; }
+ float GetYFOVDegrees() { return RadToDegree(GetYFOVRadians()); }
+
+ // Query horizontal projection center offset as a distance away from the
+ // one-eye [-1,1] unit viewport.
+ // Positive return value should be used for left eye, negative for right eye.
+ float GetProjectionCenterOffset() { updateIfDirty(); return ProjectionCenterOffset; }
+
+ // GetDistortionConfig isn't const because XCenterOffset bay need to be recomputed.
+ const DistortionConfig& GetDistortionConfig() { updateIfDirty(); return Distortion; }
+
+ // Returns DistortionScale factor by which input texture size is increased to make
+ // post-distortion result distortion fit the viewport.
+ float GetDistortionScale() { updateIfDirty(); return Distortion.Scale; }
+
+ // Returns the size of a pixel within 2D coordinate system.
+ float Get2DUnitPixel() { updateIfDirty(); return (2.0f / (FovPixels * Distortion.Scale)); }
+
+ // Returns full set of Stereo rendering parameters for the specified eye.
+ const StereoEyeParams& GetEyeRenderParams(StereoEye eye);
+
+private:
+
+ void updateIfDirty() { if (DirtyFlag) updateComputedState(); }
+ void updateComputedState();
+
+ void updateDistortionOffsetAndScale();
+ void updateProjectionOffset();
+ void update2D();
+ void updateEyeParams();
+
+
+ // *** Modifiable State
+
+ StereoMode Mode;
+ float InterpupillaryDistance;
+ float AspectMultiplier; // Multiplied into aspect ratio to change it.
+ HMDInfo HMD;
+ DistortionConfig Distortion;
+ float DistortionFitX, DistortionFitY; // In [-1,1] half-screen viewport units.
+ Viewport FullView; // Entire window viewport.
+
+ float Area2DFov; // FOV range mapping to [-1, 1] 2D area.
+
+ // *** Computed State
+
+ bool DirtyFlag; // Set when any if the modifiable state changed.
+ bool IPDOverride; // True after SetIPD was called.
+ float YFov; // Vertical FOV.
+ float Aspect; // Aspect ratio: (w/h)*AspectMultiplier.
+ float ProjectionCenterOffset;
+ StereoEyeParams EyeRenderParams[2];
+
+
+ // ** 2D Rendering
+
+ // Number of 2D pixels in the FOV. This defines [-1,1] coordinate range for 2D.
+ float FovPixels;
+ Matrix4f OrthoCenter;
+ float OrthoPixelOffset;
+};
+
+
+}}} // OVR::Util::Render
+
+#endif