summaryrefslogtreecommitdiffstats
path: root/LibOVR/Src/Util
diff options
context:
space:
mode:
authorBrad Davis <[email protected]>2014-07-24 16:47:31 -0700
committerBrad Davis <[email protected]>2014-07-24 16:47:31 -0700
commit0f49ce8fc6aa54224e4c0d6fda8c4527ad39cce1 (patch)
treeda07ebc6a7f75185bda857dd5f1c34710b416a93 /LibOVR/Src/Util
parentca79271759ff7eecd22ec5c4db438370fe51d687 (diff)
0.4 Win-Beta0.4.0
Diffstat (limited to 'LibOVR/Src/Util')
-rw-r--r--LibOVR/Src/Util/Util_ImageWindow.cpp46
-rw-r--r--LibOVR/Src/Util/Util_ImageWindow.h17
-rw-r--r--LibOVR/Src/Util/Util_Interface.h3
-rw-r--r--LibOVR/Src/Util/Util_LatencyTest.cpp570
-rw-r--r--LibOVR/Src/Util/Util_LatencyTest.h173
-rw-r--r--LibOVR/Src/Util/Util_LatencyTest2.cpp191
-rw-r--r--LibOVR/Src/Util/Util_LatencyTest2.h238
-rw-r--r--LibOVR/Src/Util/Util_LatencyTest2Reader.cpp118
-rw-r--r--LibOVR/Src/Util/Util_LatencyTest2Reader.h63
-rw-r--r--LibOVR/Src/Util/Util_LatencyTest2State.h96
-rw-r--r--LibOVR/Src/Util/Util_LongPollThread.cpp96
-rw-r--r--LibOVR/Src/Util/Util_LongPollThread.h72
-rw-r--r--LibOVR/Src/Util/Util_Render_Stereo.cpp136
-rw-r--r--LibOVR/Src/Util/Util_Render_Stereo.h38
-rw-r--r--LibOVR/Src/Util/Util_Settings.cpp312
-rw-r--r--LibOVR/Src/Util/Util_Settings.h83
16 files changed, 972 insertions, 1280 deletions
diff --git a/LibOVR/Src/Util/Util_ImageWindow.cpp b/LibOVR/Src/Util/Util_ImageWindow.cpp
index cb091c7..d937a25 100644
--- a/LibOVR/Src/Util/Util_ImageWindow.cpp
+++ b/LibOVR/Src/Util/Util_ImageWindow.cpp
@@ -23,12 +23,13 @@ See the License for the specific language governing permissions and
limitations under the License.
*************************************************************************************/
-#include "../../Include/OVR.h"
+#include "../../Include/OVR_Kernel.h"
#include "Util_ImageWindow.h"
#if defined(OVR_OS_WIN32)
+#define WIN32_LEAN_AND_MEAN
#include <Windows.h>
#include "DWrite.h"
@@ -51,7 +52,14 @@ namespace OVR { namespace Util {
ID2D1Factory* ImageWindow::pD2DFactory = NULL;
IDWriteFactory* ImageWindow::pDWriteFactory = NULL;
-ImageWindow* ImageWindow::globalWindow[4];
+
+
+// TODO(review): This appears to be (at present) necessary, the global list is accessed by the
+// render loop in Samples. In the current version, windows will just be lost when windowCount
+// exceeds MaxWindows; I've left that in place, since this is unfamiliar code. I'm not sure what
+// thread-safety guarantees this portion of the code needs to satisfy, so I don't want to
+// change it to a list or whatever. Asserts added to catch the error.
+ImageWindow* ImageWindow::globalWindow[ImageWindow::MaxWindows];
int ImageWindow::windowCount = 0;
LRESULT CALLBACK MainWndProc(
@@ -115,9 +123,9 @@ ImageWindow::ImageWindow( uint32_t width, uint32_t height ) :
writeFactory = (DWriteCreateFactoryFn)GetProcAddress( hInstWrite, "DWriteCreateFactory" );
}
- globalWindow[windowCount] = this;
-
- ++windowCount;
+ // TODO: see note where globalWindow is declared.
+ globalWindow[windowCount++ % MaxWindows] = this;
+ OVR_ASSERT(windowCount < MaxWindows);
if( pD2DFactory == NULL && createFactory && writeFactory )
{
@@ -155,7 +163,7 @@ ImageWindow::~ImageWindow()
globalWindow[i] = NULL;
break;
}
-}
+ }
if( greyBitmap )
greyBitmap->Release();
@@ -240,14 +248,14 @@ void ImageWindow::AssociateSurface( void* surface )
tmpTarget = NULL;
}
- result = tmpTarget->CreateBitmap( size, colorBitmapProps, &colorBitmap );
- if( result != S_OK )
+ if (tmpTarget)
{
- greyBitmap->Release();
- greyBitmap = NULL;
-
- tmpTarget->Release();
- tmpTarget = NULL;
+ result = tmpTarget->CreateBitmap(size, colorBitmapProps, &colorBitmap);
+ if (result != S_OK)
+ {
+ tmpTarget->Release();
+ tmpTarget = NULL;
+ }
}
pRT = tmpTarget;
}
@@ -508,4 +516,14 @@ void ImageWindow::addText( float x, float y, float r, float g, float b, OVR::Str
}}
-#endif //defined(OVR_OS_WIN32) \ No newline at end of file
+#else //defined(OVR_OS_WIN32)
+
+namespace OVR { namespace Util {
+
+ImageWindow* ImageWindow::globalWindow[4];
+int ImageWindow::windowCount = 0;
+
+}}
+
+#endif //#else //defined(OVR_OS_WIN32)
+
diff --git a/LibOVR/Src/Util/Util_ImageWindow.h b/LibOVR/Src/Util/Util_ImageWindow.h
index 4b88959..901626d 100644
--- a/LibOVR/Src/Util/Util_ImageWindow.h
+++ b/LibOVR/Src/Util/Util_ImageWindow.h
@@ -28,13 +28,14 @@ limitations under the License.
#define UTIL_IMAGEWINDOW_H
#if defined(OVR_OS_WIN32)
-#define WIN32_LEAN_AND_MEAN 1
-#include <windows.h>
+#include <WinSock2.h>
+#include <WS2tcpip.h>
+#define WIN32_LEAN_AND_MEAN
+#include <Windows.h>
#include <d2d1.h>
#include <dwrite.h>
#endif
-#include "../../Include/OVR.h"
#include "../Kernel/OVR_Hash.h"
#include "../Kernel/OVR_Array.h"
#include "../Kernel/OVR_Threads.h"
@@ -171,16 +172,16 @@ public:
void OnPaint() { }
void UpdateImage( const uint8_t* imageData, uint32_t width, uint32_t height ) { UpdateImageBW( imageData, width, height ); }
- void UpdateImageBW( const uint8_t* imageData, uint32_t width, uint32_t height ) { }
- void UpdateImageRGBA( const uint8_t* imageData, uint32_t width, uint32_t height, uint32_t pitch ) { }
+ void UpdateImageBW( const uint8_t* imageData, uint32_t width, uint32_t height ) { OVR_UNUSED( imageData ); OVR_UNUSED( width ); OVR_UNUSED( height ); }
+ void UpdateImageRGBA( const uint8_t* imageData, uint32_t width, uint32_t height, uint32_t pitch ) { OVR_UNUSED( imageData ); OVR_UNUSED( width ); OVR_UNUSED( height ); OVR_UNUSED( pitch ); }
void Complete() { }
void Process() { }
- void AssociateSurface( void* surface ) { }
+ void AssociateSurface( void* surface ) { OVR_UNUSED(surface); }
- void addCircle( float x , float y, float radius, float r, float g, float b, bool fill ) { }
- void addText( float x, float y, float r, float g, float b, OVR::String text ) { }
+ void addCircle( float x , float y, float radius, float r, float g, float b, bool fill ) { OVR_UNUSED( x ); OVR_UNUSED( y ); OVR_UNUSED( radius ); OVR_UNUSED( r ); OVR_UNUSED( g ); OVR_UNUSED( b ); OVR_UNUSED( fill ); }
+ void addText( float x, float y, float r, float g, float b, OVR::String text ) { OVR_UNUSED( x ); OVR_UNUSED( y ); OVR_UNUSED( r ); OVR_UNUSED( g ); OVR_UNUSED( b ); OVR_UNUSED( text ); }
static ImageWindow* GlobalWindow( int window ) { return globalWindow[window]; }
static int WindowCount() { return windowCount; }
diff --git a/LibOVR/Src/Util/Util_Interface.h b/LibOVR/Src/Util/Util_Interface.h
index 1bbf638..fbb7d25 100644
--- a/LibOVR/Src/Util/Util_Interface.h
+++ b/LibOVR/Src/Util/Util_Interface.h
@@ -1,6 +1,5 @@
/************************************************************************************
-PublicHeader: OVR.h
Filename : Util_Interface.h
Content : Simple interface, utilised by internal demos,
with access to wider SDK as needed.
@@ -30,7 +29,7 @@ limitations under the License.
#ifndef OVR_Util_Interface_h
#define OVR_Util_Interface_h
-#include "../../Src/OVR_CAPI.h"
+#include "../OVR_CAPI.h"
//Files left in to ease its possible return......
diff --git a/LibOVR/Src/Util/Util_LatencyTest.cpp b/LibOVR/Src/Util/Util_LatencyTest.cpp
deleted file mode 100644
index 3017c72..0000000
--- a/LibOVR/Src/Util/Util_LatencyTest.cpp
+++ /dev/null
@@ -1,570 +0,0 @@
-/************************************************************************************
-
-Filename : Util_LatencyTest.cpp
-Content : Wraps the lower level LatencyTester interface and adds functionality.
-Created : February 14, 2013
-Authors : Lee Cooper
-
-Copyright : Copyright 2014 Oculus VR, Inc. All Rights reserved.
-
-Licensed under the Oculus VR Rift SDK License Version 3.1 (the "License");
-you may not use the Oculus VR Rift SDK except in compliance with the License,
-which is provided at the time of installation or download, or which
-otherwise accompanies this software in either electronic or hard copy form.
-
-You may obtain a copy of the License at
-
-http://www.oculusvr.com/licenses/LICENSE-3.1
-
-Unless required by applicable law or agreed to in writing, the Oculus VR SDK
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
-
-*************************************************************************************/
-
-#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)
- {
- Handler.RemoveHandlerFromDevices();
-
- Device = device;
-
- if (Device != NULL)
- {
- Device->AddMessageHandler(&Handler);
-
- // Set trigger threshold.
- LatencyTestConfiguration configuration(SENSOR_DETECT_THRESHOLD, false); // No samples streaming.
- Device->SetConfiguration(configuration, true);
-
- // Set display to initial (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()->StartTestSeconds = Timer::GetSeconds();
-
- 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()->TestStartedSeconds = Timer::GetSeconds();
-
- 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 = Timer::MsPerSecond * (float) (pCurr->TestStartedSeconds - pCurr->StartTestSeconds);
- 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
deleted file mode 100644
index 0844603..0000000
--- a/LibOVR/Src/Util/Util_LatencyTest.h
+++ /dev/null
@@ -1,173 +0,0 @@
-/************************************************************************************
-
-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 2014 Oculus VR, Inc. All Rights reserved.
-
-Licensed under the Oculus VR Rift SDK License Version 3.1 (the "License");
-you may not use the Oculus VR Rift SDK except in compliance with the License,
-which is provided at the time of installation or download, or which
-otherwise accompanies this software in either electronic or hard copy form.
-
-You may obtain a copy of the License at
-
-http://www.oculusvr.com/licenses/LICENSE-3.1
-
-Unless required by applicable law or agreed to in writing, the Oculus VR SDK
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
-
-*************************************************************************************/
-
-#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();
-
- bool IsMeasuringNow() const { return (State != State_WaitingForButton); }
-
- // 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),
- StartTestSeconds(0.0),
- TestStartedSeconds(0.0)
- {}
-
- Color TargetColor;
-
- UInt32 DeviceMeasuredElapsedMilliS;
-
- bool TimedOutWaitingForTestStarted;
- bool TimedOutWaitingForColorDetected;
-
- double StartTestSeconds;
- double TestStartedSeconds;
- };
-
- 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_LatencyTest2.cpp b/LibOVR/Src/Util/Util_LatencyTest2.cpp
deleted file mode 100644
index 6fc8b1f..0000000
--- a/LibOVR/Src/Util/Util_LatencyTest2.cpp
+++ /dev/null
@@ -1,191 +0,0 @@
-/************************************************************************************
-
-Filename : Util_LatencyTest2.cpp
-Content : Wraps the lower level LatencyTester interface for DK2 and adds functionality.
-Created : March 10, 2014
-Authors : Volga Aksoy
-
-Copyright : Copyright 2014 Oculus VR, Inc. All Rights reserved.
-
-Licensed under the Oculus VR Rift SDK License Version 3.1 (the "License");
-you may not use the Oculus VR Rift SDK except in compliance with the License,
-which is provided at the time of installation or download, or which
-otherwise accompanies this software in either electronic or hard copy form.
-
-You may obtain a copy of the License at
-
-http://www.oculusvr.com/licenses/LICENSE-3.1
-
-Unless required by applicable law or agreed to in writing, the Oculus VR SDK
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
-
-*************************************************************************************/
-
-#include "Util_LatencyTest2.h"
-
-#include "../OVR_CAPI.h"
-#include "../Kernel/OVR_Log.h"
-#include "../Kernel/OVR_Timer.h"
-
-
-namespace OVR { namespace Util {
-
-//-------------------------------------------------------------------------------------
-// ***** LatencyTest2
-
-LatencyTest2::LatencyTest2(SensorDevice* device)
- : Handler(getThis())
- , TestActive(false)
- , StartTiming(-1)
- , LatencyMeasuredInSeconds(-1)
- , LastPixelReadMsg(NULL)
- , RenderColorValue(0)
- , NumMsgsBeforeSettle(0)
- , NumTestsSuccessful(0)
-{
- if (device != NULL)
- {
- SetSensorDevice(device);
- }
-}
-
-LatencyTest2::~LatencyTest2()
-{
- HmdDevice = NULL;
- LatencyTesterDev = NULL;
-
- Handler.RemoveHandlerFromDevices();
-}
-
-bool LatencyTest2::SetSensorDevice(SensorDevice* device)
-{
- Lock::Locker devLocker(&TesterLock);
-
- // Enable/Disable pixel read from HMD
- if (device != HmdDevice)
- {
- Handler.RemoveHandlerFromDevices();
-
- HmdDevice = device;
-
- if (HmdDevice != NULL)
- {
- HmdDevice->AddMessageHandler(&Handler);
- }
- }
-
- return true;
-}
-
-bool LatencyTest2::SetDisplayDevice(LatencyTestDevice* device)
-{
- Lock::Locker devLocker(&TesterLock);
-
- if (device != LatencyTesterDev)
- {
- LatencyTesterDev = device;
- if (LatencyTesterDev != NULL)
- {
- // Set display to initial (3 dashes).
- LatencyTestDisplay ltd(2, 0x40400040);
- LatencyTesterDev->SetDisplay(ltd);
- }
- }
-
- return true;
-}
-
-void LatencyTest2::BeginTest(double startTime)
-{
- Lock::Locker devLocker(&TesterLock);
-
- if (!TestActive)
- {
- TestActive = true;
- NumMsgsBeforeSettle = 0;
-
- // Go to next pixel value
- //RenderColorValue = (RenderColorValue == 0) ? 255 : 0;
- RenderColorValue = (RenderColorValue + LT2_ColorIncrement) % 256;
- RawStartTiming = LastPixelReadMsg.RawSensorTime;
-
- if (startTime > 0.0)
- StartTiming = startTime;
- else
- StartTiming = ovr_GetTimeInSeconds();
-
- }
-}
-
-void LatencyTest2::handleMessage(const MessagePixelRead& msg)
-{
- Lock::Locker devLocker(&TesterLock);
-
- // Hold onto the last message as we will use this when we start a new test
- LastPixelReadMsg = msg;
-
- // If color readback index is valid, store it in the lock-less queue.
- int readbackIndex = 0;
- if (FrameTimeRecord::ColorToReadbackIndex(&readbackIndex, msg.PixelReadValue))
- {
- RecentFrameSet.AddValue(readbackIndex, msg.FrameTimeSeconds);
- LockessRecords.SetState(RecentFrameSet);
- }
-
- NumMsgsBeforeSettle++;
-
- if (TestActive)
- {
- int pixelValueDiff = RenderColorValue - LastPixelReadMsg.PixelReadValue;
- int rawTimeDiff = LastPixelReadMsg.RawFrameTime - RawStartTiming;
-
- if (pixelValueDiff < LT2_PixelTestThreshold && pixelValueDiff > -LT2_PixelTestThreshold)
- {
- TestActive = false;
-
- LatencyMeasuredInSeconds = LastPixelReadMsg.FrameTimeSeconds - StartTiming;
- RawLatencyMeasured = rawTimeDiff;
- //LatencyMeasuredInSeconds = RawLatencyMeasured / 1000000.0;
-
- if(LatencyTesterDev && (NumTestsSuccessful % 5) == 0)
- {
- int displayNum = (int)(RawLatencyMeasured / 100.0);
- //int displayNum = NumMsgsBeforeSettle;
- //int displayNum = (int)(LatencyMeasuredInSeconds * 1000.0);
- LatencyTestDisplay ltd(1, displayNum);
- LatencyTesterDev->SetDisplay(ltd);
- }
-
- NumTestsSuccessful++;
- }
- else if (TestActive && (rawTimeDiff / 1000) > LT2_TimeoutWaitingForColorDetected)
- {
- TestActive = false;
- LatencyMeasuredInSeconds = -1;
- }
- }
-}
-
-LatencyTest2::PixelReadHandler::~PixelReadHandler()
-{
- RemoveHandlerFromDevices();
-}
-
-void LatencyTest2::PixelReadHandler::OnMessage(const Message& msg)
-{
- if(msg.Type == Message_PixelRead)
- pLatencyTestUtil->handleMessage(static_cast<const MessagePixelRead&>(msg));
-}
-
-bool LatencyTest2::DisplayScreenColor(Color& colorToDisplay)
-{
- Lock::Locker devLocker(&TesterLock);
- colorToDisplay = Color(RenderColorValue, RenderColorValue, RenderColorValue, 255);
-
- return TestActive;
-}
-
-}} // namespace OVR::Util
diff --git a/LibOVR/Src/Util/Util_LatencyTest2.h b/LibOVR/Src/Util/Util_LatencyTest2.h
deleted file mode 100644
index 61e8477..0000000
--- a/LibOVR/Src/Util/Util_LatencyTest2.h
+++ /dev/null
@@ -1,238 +0,0 @@
-/************************************************************************************
-
-PublicHeader: OVR.h
-Filename : Util_LatencyTest2.h
-Content : Wraps the lower level LatencyTester interface for DK2 and adds functionality.
-Created : March 10, 2014
-Authors : Volga Aksoy
-
-Copyright : Copyright 2014 Oculus VR, Inc. All Rights reserved.
-
-Licensed under the Oculus VR Rift SDK License Version 3.1 (the "License");
-you may not use the Oculus VR Rift SDK except in compliance with the License,
-which is provided at the time of installation or download, or which
-otherwise accompanies this software in either electronic or hard copy form.
-
-You may obtain a copy of the License at
-
-http://www.oculusvr.com/licenses/LICENSE-3.1
-
-Unless required by applicable law or agreed to in writing, the Oculus VR SDK
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
-
-*************************************************************************************/
-
-#ifndef OVR_Util_LatencyTest2_h
-#define OVR_Util_LatencyTest2_h
-
-#include "../OVR_Device.h"
-
-#include "../Kernel/OVR_String.h"
-#include "../Kernel/OVR_List.h"
-#include "../Kernel/OVR_Lockless.h"
-
-namespace OVR { namespace Util {
-
-
-enum {
- LT2_ColorIncrement = 32,
- LT2_PixelTestThreshold = LT2_ColorIncrement / 3,
- LT2_IncrementCount = 256 / LT2_ColorIncrement,
- LT2_TimeoutWaitingForColorDetected = 1000 // 1 second
-};
-
-//-------------------------------------------------------------------------------------
-
-// Describes frame scanout time used for latency testing.
-struct FrameTimeRecord
-{
- int ReadbackIndex;
- double TimeSeconds;
-
- // Utility functions to convert color to readBack indices and back.
- // The purpose of ReadbackIndex is to allow direct comparison by value.
-
- static bool ColorToReadbackIndex(int *readbackIndex, unsigned char color)
- {
- int compareColor = color - LT2_ColorIncrement/2;
- int index = color / LT2_ColorIncrement; // Use color without subtraction due to rounding.
- int delta = compareColor - index * LT2_ColorIncrement;
-
- if ((delta < LT2_PixelTestThreshold) && (delta > -LT2_PixelTestThreshold))
- {
- *readbackIndex = index;
- return true;
- }
- return false;
- }
-
- static unsigned char ReadbackIndexToColor(int readbackIndex)
- {
- OVR_ASSERT(readbackIndex < LT2_IncrementCount);
- return (unsigned char)(readbackIndex * LT2_ColorIncrement + LT2_ColorIncrement/2);
- }
-};
-
-// FrameTimeRecordSet is a container holding multiple consecutive frame timing records
-// returned from the lock-less state. Used by FrameTimeManager.
-
-struct FrameTimeRecordSet
-{
- enum {
- RecordCount = 4,
- RecordMask = RecordCount - 1
- };
- FrameTimeRecord Records[RecordCount];
- int NextWriteIndex;
-
- FrameTimeRecordSet()
- {
- NextWriteIndex = 0;
- memset(this, 0, sizeof(FrameTimeRecordSet));
- }
-
- void AddValue(int readValue, double timeSeconds)
- {
- Records[NextWriteIndex].ReadbackIndex = readValue;
- Records[NextWriteIndex].TimeSeconds = timeSeconds;
- NextWriteIndex ++;
- if (NextWriteIndex == RecordCount)
- NextWriteIndex = 0;
- }
- // Matching should be done starting from NextWrite index
- // until wrap-around
-
- const FrameTimeRecord& operator [] (int i) const
- {
- return Records[(NextWriteIndex + i) & RecordMask];
- }
-
- const FrameTimeRecord& GetMostRecentFrame()
- {
- return Records[(NextWriteIndex - 1) & RecordMask];
- }
-
- // Advances I to absolute color index
- bool FindReadbackIndex(int* i, int readbackIndex) const
- {
- for (; *i < RecordCount; (*i)++)
- {
- if ((*this)[*i].ReadbackIndex == readbackIndex)
- return true;
- }
- return false;
- }
-
- bool IsAllZeroes() const
- {
- for (int i = 0; i < RecordCount; i++)
- if (Records[i].ReadbackIndex != 0)
- return false;
- return true;
- }
-};
-
-
-//-------------------------------------------------------------------------------------
-// ***** LatencyTest2
-//
-// LatencyTest2 utility class wraps the low level SensorDevice 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 SensorDevice 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 LatencyTest2 : public NewOverrideBase
-{
-public:
- LatencyTest2(SensorDevice* device = NULL);
- ~LatencyTest2();
-
- // Set the Latency Tester device that we'll use to send commands to and receive
- // notification messages from.
- bool SetSensorDevice(SensorDevice* device);
- bool SetDisplayDevice(LatencyTestDevice* device);
-
- // Returns true if this LatencyTestUtil has a Latency Tester device.
- bool HasDisplayDevice() const { return LatencyTesterDev.GetPtr() != NULL; }
- bool HasDevice() const { return Handler.IsHandlerInstalled(); }
-
- bool DisplayScreenColor(Color& colorToDisplay);
- //const char* GetResultsString();
-
- // Begin test. Equivalent to pressing the button on the latency tester.
- void BeginTest(double startTime = -1.0f);
- bool IsMeasuringNow() const { return TestActive; }
- double GetMeasuredLatency() const { return LatencyMeasuredInSeconds; }
-
-//
- FrameTimeRecordSet GetLocklessState() { return LockessRecords.GetState(); }
-
-private:
- LatencyTest2* getThis() { return this; }
-
- enum LatencyTestMessageType
- {
- LatencyTest_None,
- LatencyTest_Timer,
- LatencyTest_ProcessInputs,
- };
-
- void handleMessage(const MessagePixelRead& msg);
-
- class PixelReadHandler : public MessageHandler
- {
- LatencyTest2* pLatencyTestUtil;
- public:
- PixelReadHandler(LatencyTest2* latencyTester) : pLatencyTestUtil(latencyTester) { }
- ~PixelReadHandler();
-
- virtual void OnMessage(const Message& msg);
- };
- PixelReadHandler Handler;
-
- Ptr<SensorDevice> HmdDevice;
- Ptr<LatencyTestDevice> LatencyTesterDev;
-
- Lock TesterLock;
- bool TestActive;
- unsigned char RenderColorValue;
- MessagePixelRead LastPixelReadMsg;
- double StartTiming;
- unsigned int RawStartTiming;
- UInt32 RawLatencyMeasured;
- double LatencyMeasuredInSeconds;
- int NumMsgsBeforeSettle;
- unsigned int NumTestsSuccessful;
-
- // MA:
- // Frames are added here, then copied into lockess state
- FrameTimeRecordSet RecentFrameSet;
- LocklessUpdater<FrameTimeRecordSet> LockessRecords;
-};
-
-
-
-}} // namespace OVR::Util
-
-#endif // OVR_Util_LatencyTest2_h
diff --git a/LibOVR/Src/Util/Util_LatencyTest2Reader.cpp b/LibOVR/Src/Util/Util_LatencyTest2Reader.cpp
new file mode 100644
index 0000000..493f779
--- /dev/null
+++ b/LibOVR/Src/Util/Util_LatencyTest2Reader.cpp
@@ -0,0 +1,118 @@
+/************************************************************************************
+
+Filename : Util_LatencyTest2Reader.cpp
+Content : Shared functionality for the DK2 latency tester
+Created : July 8, 2014
+Authors : Volga Aksoy, Chris Taylor
+
+Copyright : Copyright 2014 Oculus VR, Inc. All Rights reserved.
+
+Licensed under the Oculus VR Rift SDK License Version 3.1 (the "License");
+you may not use the Oculus VR Rift SDK except in compliance with the License,
+which is provided at the time of installation or download, or which
+otherwise accompanies this software in either electronic or hard copy form.
+
+You may obtain a copy of the License at
+
+http://www.oculusvr.com/licenses/LICENSE-3.1
+
+Unless required by applicable law or agreed to in writing, the Oculus VR SDK
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+*************************************************************************************/
+
+#include "Util_LatencyTest2Reader.h"
+
+namespace OVR { namespace Util {
+
+
+//// FrameTimeRecord
+
+bool FrameTimeRecord::ColorToReadbackIndex(int *readbackIndex, unsigned char color)
+{
+ int compareColor = color - LT2_ColorIncrement/2;
+ int index = color / LT2_ColorIncrement; // Use color without subtraction due to rounding.
+ int delta = compareColor - index * LT2_ColorIncrement;
+
+ if ((delta < LT2_PixelTestThreshold) && (delta > -LT2_PixelTestThreshold))
+ {
+ *readbackIndex = index;
+ return true;
+ }
+ return false;
+}
+
+unsigned char FrameTimeRecord::ReadbackIndexToColor(int readbackIndex)
+{
+ OVR_ASSERT(readbackIndex < LT2_IncrementCount);
+ return (unsigned char)(readbackIndex * LT2_ColorIncrement + LT2_ColorIncrement/2);
+}
+
+
+//// FrameTimeRecordSet
+
+FrameTimeRecordSet::FrameTimeRecordSet()
+{
+ NextWriteIndex = 0;
+ memset(this, 0, sizeof(FrameTimeRecordSet));
+}
+
+void FrameTimeRecordSet::AddValue(int readValue, double timeSeconds)
+{
+ Records[NextWriteIndex].ReadbackIndex = readValue;
+ Records[NextWriteIndex].TimeSeconds = timeSeconds;
+ NextWriteIndex++;
+ if (NextWriteIndex == RecordCount)
+ NextWriteIndex = 0;
+}
+// Matching should be done starting from NextWrite index
+// until wrap-around
+
+const FrameTimeRecord& FrameTimeRecordSet::operator [] (int i) const
+{
+ return Records[(NextWriteIndex + i) & RecordMask];
+}
+
+const FrameTimeRecord& FrameTimeRecordSet::GetMostRecentFrame()
+{
+ return Records[(NextWriteIndex - 1) & RecordMask];
+}
+
+// Advances I to absolute color index
+bool FrameTimeRecordSet::FindReadbackIndex(int* i, int readbackIndex) const
+{
+ for (; *i < RecordCount; (*i)++)
+ {
+ if ((*this)[*i].ReadbackIndex == readbackIndex)
+ return true;
+ }
+ return false;
+}
+
+bool FrameTimeRecordSet::IsAllZeroes() const
+{
+ for (int i = 0; i < RecordCount; i++)
+ if (Records[i].ReadbackIndex != 0)
+ return false;
+ return true;
+}
+
+
+//// RecordStateReader
+
+void RecordStateReader::GetRecordSet(FrameTimeRecordSet& recordset)
+{
+ if(!Updater)
+ {
+ return;
+ }
+
+ recordset = Updater->SharedLatencyTestState.GetState();
+ return;
+}
+
+
+}} // namespace OVR::Util
diff --git a/LibOVR/Src/Util/Util_LatencyTest2Reader.h b/LibOVR/Src/Util/Util_LatencyTest2Reader.h
new file mode 100644
index 0000000..57f70be
--- /dev/null
+++ b/LibOVR/Src/Util/Util_LatencyTest2Reader.h
@@ -0,0 +1,63 @@
+/************************************************************************************
+
+Filename : Util_LatencyTest2Reader.h
+Content : Shared functionality for the DK2 latency tester
+Created : July 8, 2014
+Authors : Volga Aksoy, Chris Taylor
+
+Copyright : Copyright 2014 Oculus VR, Inc. All Rights reserved.
+
+Licensed under the Oculus VR Rift SDK License Version 3.1 (the "License");
+you may not use the Oculus VR Rift SDK except in compliance with the License,
+which is provided at the time of installation or download, or which
+otherwise accompanies this software in either electronic or hard copy form.
+
+You may obtain a copy of the License at
+
+http://www.oculusvr.com/licenses/LICENSE-3.1
+
+Unless required by applicable law or agreed to in writing, the Oculus VR SDK
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+*************************************************************************************/
+
+#ifndef OVR_Util_LatencyTest2Reader_h
+#define OVR_Util_LatencyTest2Reader_h
+
+#include "../Tracking/Tracking_SensorState.h"
+#include "Util_LatencyTest2State.h"
+
+namespace OVR { namespace Util {
+
+
+//-----------------------------------------------------------------------------
+// RecordStateReader
+
+// User interface to retrieve pose from the sensor fusion subsystem
+class RecordStateReader : public NewOverrideBase
+{
+protected:
+ const Tracking::CombinedSharedStateUpdater* Updater;
+
+public:
+ RecordStateReader()
+ : Updater(NULL)
+ {
+ }
+
+ // Initialize the updater
+ void SetUpdater(const Tracking::CombinedSharedStateUpdater *updater)
+ {
+ Updater = updater;
+ }
+
+ void GetRecordSet(FrameTimeRecordSet& recordset);
+};
+
+
+}} // namespace OVR::Util
+
+#endif // OVR_Util_LatencyTest2Reader_h
diff --git a/LibOVR/Src/Util/Util_LatencyTest2State.h b/LibOVR/Src/Util/Util_LatencyTest2State.h
new file mode 100644
index 0000000..3ea4e76
--- /dev/null
+++ b/LibOVR/Src/Util/Util_LatencyTest2State.h
@@ -0,0 +1,96 @@
+/************************************************************************************
+
+Filename : Util_LatencyTest2Reader.h
+Content : Shared functionality for the DK2 latency tester
+Created : July 8, 2014
+Authors : Volga Aksoy, Chris Taylor
+
+Copyright : Copyright 2014 Oculus VR, Inc. All Rights reserved.
+
+Licensed under the Oculus VR Rift SDK License Version 3.1 (the "License");
+you may not use the Oculus VR Rift SDK except in compliance with the License,
+which is provided at the time of installation or download, or which
+otherwise accompanies this software in either electronic or hard copy form.
+
+You may obtain a copy of the License at
+
+http://www.oculusvr.com/licenses/LICENSE-3.1
+
+Unless required by applicable law or agreed to in writing, the Oculus VR SDK
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+*************************************************************************************/
+
+#ifndef OVR_Util_LatencyTest2_State_h
+#define OVR_Util_LatencyTest2_State_h
+
+#include "../Kernel/OVR_Lockless.h"
+
+namespace OVR { namespace Util {
+
+
+enum LatencyTester2Constants
+{
+ LT2_ColorIncrement = 32,
+ LT2_PixelTestThreshold = LT2_ColorIncrement / 3,
+ LT2_IncrementCount = 256 / LT2_ColorIncrement,
+ LT2_TimeoutWaitingForColorDetected = 1000 // 1 second
+};
+
+
+//-------------------------------------------------------------------------------------
+// FrameTimeRecord
+
+// Describes frame scan-out time used for latency testing.
+struct FrameTimeRecord
+{
+ int ReadbackIndex;
+ double TimeSeconds;
+
+ // Utility functions to convert color to readBack indices and back.
+ // The purpose of ReadbackIndex is to allow direct comparison by value.
+
+ static bool ColorToReadbackIndex(int *readbackIndex, unsigned char color);
+ static unsigned char ReadbackIndexToColor(int readbackIndex);
+};
+
+
+//-----------------------------------------------------------------------------
+// FrameTimeRecordSet
+
+// FrameTimeRecordSet is a container holding multiple consecutive frame timing records
+// returned from the lock-less state. Used by FrameTimeManager.
+struct FrameTimeRecordSet
+{
+ enum {
+ RecordCount = 4,
+ RecordMask = RecordCount - 1
+ };
+ FrameTimeRecord Records[RecordCount];
+ int NextWriteIndex;
+
+ FrameTimeRecordSet();
+
+ void AddValue(int readValue, double timeSeconds);
+ // Matching should be done starting from NextWrite index
+ // until wrap-around
+
+ const FrameTimeRecord& operator [] (int i) const;
+
+ const FrameTimeRecord& GetMostRecentFrame();
+
+ // Advances I to absolute color index
+ bool FindReadbackIndex(int* i, int readbackIndex) const;
+
+ bool IsAllZeroes() const;
+};
+
+typedef LocklessUpdater<FrameTimeRecordSet, FrameTimeRecordSet> LockessRecordUpdater;
+
+
+}} // namespace OVR::Util
+
+#endif // OVR_Util_LatencyTest2_State_h
diff --git a/LibOVR/Src/Util/Util_LongPollThread.cpp b/LibOVR/Src/Util/Util_LongPollThread.cpp
new file mode 100644
index 0000000..c7c5c5d
--- /dev/null
+++ b/LibOVR/Src/Util/Util_LongPollThread.cpp
@@ -0,0 +1,96 @@
+/************************************************************************************
+
+Filename : Util_LongPollThread.cpp
+Content : Allows us to do all long polling tasks from a single thread to minimize deadlock risk
+Created : June 30, 2013
+Authors : Chris Taylor
+
+Copyright : Copyright 2014 Oculus VR, Inc. All Rights reserved.
+
+Licensed under the Oculus VR Rift SDK License Version 3.1 (the "License");
+you may not use the Oculus VR Rift SDK except in compliance with the License,
+which is provided at the time of installation or download, or which
+otherwise accompanies this software in either electronic or hard copy form.
+
+You may obtain a copy of the License at
+
+http://www.oculusvr.com/licenses/LICENSE-3.1
+
+Unless required by applicable law or agreed to in writing, the Oculus VR SDK
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+*************************************************************************************/
+
+#include "Util_LongPollThread.h"
+#include "Util_Watchdog.h"
+
+OVR_DEFINE_SINGLETON(OVR::Util::LongPollThread);
+
+namespace OVR { namespace Util {
+
+
+void LongPollThread::AddPollFunc(Observer<PollFunc>* func)
+{
+ func->Observe(PollSubject);
+}
+
+LongPollThread::LongPollThread() :
+ Terminated(false)
+{
+ Start();
+
+ PushDestroyCallbacks();
+}
+
+LongPollThread::~LongPollThread()
+{
+ fireTermination();
+
+ Join();
+}
+
+void LongPollThread::OnThreadDestroy()
+{
+ fireTermination();
+}
+
+void LongPollThread::Wake()
+{
+ WakeEvent.SetEvent();
+}
+
+void LongPollThread::fireTermination()
+{
+ Terminated = true;
+ Wake();
+}
+
+void LongPollThread::OnSystemDestroy()
+{
+ Release();
+}
+
+int LongPollThread::Run()
+{
+ SetThreadName("LongPoll");
+ WatchDog watchdog("LongPoll");
+
+ // While not terminated,
+ do
+ {
+ watchdog.Feed(10000);
+
+ PollSubject->Call();
+
+ WakeEvent.Wait(WakeupInterval);
+ WakeEvent.ResetEvent();
+ } while (!Terminated);
+
+ return 0;
+}
+
+
+}} // namespace OVR::Util
diff --git a/LibOVR/Src/Util/Util_LongPollThread.h b/LibOVR/Src/Util/Util_LongPollThread.h
new file mode 100644
index 0000000..5183e2f
--- /dev/null
+++ b/LibOVR/Src/Util/Util_LongPollThread.h
@@ -0,0 +1,72 @@
+/************************************************************************************
+
+Filename : Util_LongPollThread.h
+Content : Allows us to do all long polling tasks from a single thread to minimize deadlock risk
+Created : June 30, 2013
+Authors : Chris Taylor
+
+Copyright : Copyright 2014 Oculus VR, Inc. All Rights reserved.
+
+Licensed under the Oculus VR Rift SDK License Version 3.1 (the "License");
+you may not use the Oculus VR Rift SDK except in compliance with the License,
+which is provided at the time of installation or download, or which
+otherwise accompanies this software in either electronic or hard copy form.
+
+You may obtain a copy of the License at
+
+http://www.oculusvr.com/licenses/LICENSE-3.1
+
+Unless required by applicable law or agreed to in writing, the Oculus VR SDK
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+*************************************************************************************/
+
+#ifndef OVR_Util_LongPollThread_h
+#define OVR_Util_LongPollThread_h
+
+#include "../Kernel/OVR_Timer.h"
+#include "../Kernel/OVR_Atomic.h"
+#include "../Kernel/OVR_Allocator.h"
+#include "../Kernel/OVR_String.h"
+#include "../Kernel/OVR_System.h"
+#include "../Kernel/OVR_Threads.h"
+#include "../Kernel/OVR_Observer.h"
+
+namespace OVR { namespace Util {
+
+
+//-----------------------------------------------------------------------------
+// LongPollThread
+
+// This thread runs long-polling subsystems that wake up every second or so
+// The motivation is to reduce the number of threads that are running to minimize the risk of deadlock
+class LongPollThread : public Thread, public SystemSingletonBase<LongPollThread>
+{
+ OVR_DECLARE_SINGLETON(LongPollThread);
+ virtual void OnThreadDestroy();
+
+public:
+ typedef Delegate0<void> PollFunc;
+ static const int WakeupInterval = 1000; // milliseconds
+
+ void AddPollFunc(Observer<PollFunc>* func);
+
+ void Wake();
+
+protected:
+ ObserverScope<PollFunc> PollSubject;
+
+ bool Terminated;
+ Event WakeEvent;
+ void fireTermination();
+
+ virtual int Run();
+};
+
+
+}} // namespace OVR::Util
+
+#endif // OVR_Util_LongPollThread_h
diff --git a/LibOVR/Src/Util/Util_Render_Stereo.cpp b/LibOVR/Src/Util/Util_Render_Stereo.cpp
index e84381e..6937141 100644
--- a/LibOVR/Src/Util/Util_Render_Stereo.cpp
+++ b/LibOVR/Src/Util/Util_Render_Stereo.cpp
@@ -25,10 +25,11 @@ limitations under the License.
*************************************************************************************/
#include "Util_Render_Stereo.h"
-#include "../OVR_SensorFusion.h"
namespace OVR { namespace Util { namespace Render {
+using namespace OVR::Tracking;
+
//-----------------------------------------------------------------------------------
// **** Useful debug functions.
@@ -442,7 +443,7 @@ const StereoEyeParamsWithOrtho& StereoConfig::GetEyeRenderParams(StereoEye eye)
UpdateComputedState();
}
- static const UByte eyeParamIndices[3] = { 0, 0, 1 };
+ static const uint8_t eyeParamIndices[3] = { 0, 0, 1 };
OVR_ASSERT(eye < sizeof(eyeParamIndices));
return EyeRenderParams[eyeParamIndices[eye]];
@@ -787,13 +788,13 @@ static const int DMA_NumTrisPerEye = (DMA_GridSize)*(DMA_GridSize)*2;
-void DistortionMeshDestroy ( DistortionMeshVertexData *pVertices, UInt16 *pTriangleMeshIndices )
+void DistortionMeshDestroy ( DistortionMeshVertexData *pVertices, uint16_t *pTriangleMeshIndices )
{
OVR_FREE ( pVertices );
OVR_FREE ( pTriangleMeshIndices );
}
-void DistortionMeshCreate ( DistortionMeshVertexData **ppVertices, UInt16 **ppTriangleListIndices,
+void DistortionMeshCreate ( DistortionMeshVertexData **ppVertices, uint16_t **ppTriangleListIndices,
int *pNumVertices, int *pNumTriangles,
const StereoEyeParams &stereoParams, const HmdRenderInfo &hmdRenderInfo )
{
@@ -811,7 +812,7 @@ void DistortionMeshCreate ( DistortionMeshVertexData **ppVertices, UInt16 **ppTr
// Generate distortion mesh for a eye.
-void DistortionMeshCreate( DistortionMeshVertexData **ppVertices, UInt16 **ppTriangleListIndices,
+void DistortionMeshCreate( DistortionMeshVertexData **ppVertices, uint16_t **ppTriangleListIndices,
int *pNumVertices, int *pNumTriangles,
bool rightEye,
const HmdRenderInfo &hmdRenderInfo,
@@ -822,7 +823,7 @@ void DistortionMeshCreate( DistortionMeshVertexData **ppVertices, UInt16 **ppTri
*ppVertices = (DistortionMeshVertexData*)
OVR_ALLOC( sizeof(DistortionMeshVertexData) * (*pNumVertices) );
- *ppTriangleListIndices = (UInt16*) OVR_ALLOC( sizeof(UInt16) * (*pNumTriangles) * 3 );
+ *ppTriangleListIndices = (uint16_t*) OVR_ALLOC( sizeof(uint16_t) * (*pNumTriangles) * 3 );
if (!*ppVertices || !*ppTriangleListIndices)
{
@@ -870,11 +871,16 @@ void DistortionMeshCreate( DistortionMeshVertexData **ppVertices, UInt16 **ppTri
sourceCoordNDC.y = 2.0f * ( (float)y / (float)DMA_GridSize ) - 1.0f;
Vector2f tanEyeAngle = TransformRendertargetNDCToTanFovSpace ( eyeToSourceNDC, sourceCoordNDC );
- // This is the function that does the really heavy lifting.
+ // Find a corresponding screen position.
+ // Note - this function does not have to be precise - we're just trying to match the mesh tessellation
+ // with the shape of the distortion to minimise the number of trianlges needed.
Vector2f screenNDC = TransformTanFovSpaceToScreenNDC ( distortion, tanEyeAngle, false );
+ // ...but don't let verts overlap to the other eye.
+ screenNDC.x = Alg::Max ( -1.0f, Alg::Min ( screenNDC.x, 1.0f ) );
+ screenNDC.y = Alg::Max ( -1.0f, Alg::Min ( screenNDC.y, 1.0f ) );
- // We then need RGB UVs. Since chromatic aberration is generated from screen coords, not
- // directly from texture NDCs, we can't just use tanEyeAngle, we need to go the long way round.
+ // From those screen positions, we then need (effectively) RGB UVs.
+ // This is the function that actually matters when doing the distortion calculation.
Vector2f tanEyeAnglesR, tanEyeAnglesG, tanEyeAnglesB;
TransformScreenNDCToTanFovSpaceChroma ( &tanEyeAnglesR, &tanEyeAnglesG, &tanEyeAnglesB,
distortion, screenNDC );
@@ -883,7 +889,6 @@ void DistortionMeshCreate( DistortionMeshVertexData **ppVertices, UInt16 **ppTri
pcurVert->TanEyeAnglesG = tanEyeAnglesG;
pcurVert->TanEyeAnglesB = tanEyeAnglesB;
-
HmdShutterTypeEnum shutterType = hmdRenderInfo.Shutter.Type;
switch ( shutterType )
{
@@ -914,17 +919,15 @@ void DistortionMeshCreate( DistortionMeshVertexData **ppVertices, UInt16 **ppTri
}
// Fade out at texture edges.
+ // The furthest out will be the blue channel, because of chromatic aberration (true of any standard lens)
+ Vector2f sourceTexCoordBlueNDC = TransformTanFovSpaceToRendertargetNDC ( eyeToSourceNDC, tanEyeAnglesB );
float edgeFadeIn = ( 1.0f / fadeOutBorderFraction ) *
- ( 1.0f - Alg::Max ( Alg::Abs ( sourceCoordNDC.x ), Alg::Abs ( sourceCoordNDC.y ) ) );
+ ( 1.0f - Alg::Max ( Alg::Abs ( sourceTexCoordBlueNDC.x ), Alg::Abs ( sourceTexCoordBlueNDC.y ) ) );
// Also fade out at screen edges.
float edgeFadeInScreen = ( 2.0f / fadeOutBorderFraction ) *
( 1.0f - Alg::Max ( Alg::Abs ( screenNDC.x ), Alg::Abs ( screenNDC.y ) ) );
edgeFadeIn = Alg::Min ( edgeFadeInScreen, edgeFadeIn );
- // Don't let verts overlap to the other eye.
- screenNDC.x = Alg::Max ( -1.0f, Alg::Min ( screenNDC.x, 1.0f ) );
- screenNDC.y = Alg::Max ( -1.0f, Alg::Min ( screenNDC.y, 1.0f ) );
-
pcurVert->Shade = Alg::Max ( 0.0f, Alg::Min ( edgeFadeIn, 1.0f ) );
pcurVert->ScreenPosNDC.x = 0.5f * screenNDC.x - 0.5f + xOffset;
pcurVert->ScreenPosNDC.y = -screenNDC.y;
@@ -935,7 +938,7 @@ void DistortionMeshCreate( DistortionMeshVertexData **ppVertices, UInt16 **ppTri
// Populate index buffer info
- UInt16 *pcurIndex = *ppTriangleListIndices;
+ uint16_t *pcurIndex = *ppTriangleListIndices;
for ( int triNum = 0; triNum < DMA_GridSize * DMA_GridSize; triNum++ )
{
@@ -982,23 +985,23 @@ void DistortionMeshCreate( DistortionMeshVertexData **ppVertices, UInt16 **ppTri
// so linear interpolation works better & we can use fewer tris.
if ( ( x < DMA_GridSize/2 ) != ( y < DMA_GridSize/2 ) ) // != is logical XOR
{
- *pcurIndex++ = (UInt16)FirstVertex;
- *pcurIndex++ = (UInt16)FirstVertex+1;
- *pcurIndex++ = (UInt16)FirstVertex+(DMA_GridSize+1)+1;
+ *pcurIndex++ = (uint16_t)FirstVertex;
+ *pcurIndex++ = (uint16_t)FirstVertex+1;
+ *pcurIndex++ = (uint16_t)FirstVertex+(DMA_GridSize+1)+1;
- *pcurIndex++ = (UInt16)FirstVertex+(DMA_GridSize+1)+1;
- *pcurIndex++ = (UInt16)FirstVertex+(DMA_GridSize+1);
- *pcurIndex++ = (UInt16)FirstVertex;
+ *pcurIndex++ = (uint16_t)FirstVertex+(DMA_GridSize+1)+1;
+ *pcurIndex++ = (uint16_t)FirstVertex+(DMA_GridSize+1);
+ *pcurIndex++ = (uint16_t)FirstVertex;
}
else
{
- *pcurIndex++ = (UInt16)FirstVertex;
- *pcurIndex++ = (UInt16)FirstVertex+1;
- *pcurIndex++ = (UInt16)FirstVertex+(DMA_GridSize+1);
+ *pcurIndex++ = (uint16_t)FirstVertex;
+ *pcurIndex++ = (uint16_t)FirstVertex+1;
+ *pcurIndex++ = (uint16_t)FirstVertex+(DMA_GridSize+1);
- *pcurIndex++ = (UInt16)FirstVertex+1;
- *pcurIndex++ = (UInt16)FirstVertex+(DMA_GridSize+1)+1;
- *pcurIndex++ = (UInt16)FirstVertex+(DMA_GridSize+1);
+ *pcurIndex++ = (uint16_t)FirstVertex+1;
+ *pcurIndex++ = (uint16_t)FirstVertex+(DMA_GridSize+1)+1;
+ *pcurIndex++ = (uint16_t)FirstVertex+(DMA_GridSize+1);
}
}
}
@@ -1013,13 +1016,13 @@ static const int HMA_NumVertsPerEye = (HMA_GridSize+1)*(HMA_GridSize+1);
static const int HMA_NumTrisPerEye = (HMA_GridSize)*(HMA_GridSize)*2;
-void HeightmapMeshDestroy ( HeightmapMeshVertexData *pVertices, UInt16 *pTriangleMeshIndices )
+void HeightmapMeshDestroy ( HeightmapMeshVertexData *pVertices, uint16_t *pTriangleMeshIndices )
{
OVR_FREE ( pVertices );
OVR_FREE ( pTriangleMeshIndices );
}
-void HeightmapMeshCreate ( HeightmapMeshVertexData **ppVertices, UInt16 **ppTriangleListIndices,
+void HeightmapMeshCreate ( HeightmapMeshVertexData **ppVertices, uint16_t **ppTriangleListIndices,
int *pNumVertices, int *pNumTriangles,
const StereoEyeParams &stereoParams, const HmdRenderInfo &hmdRenderInfo )
{
@@ -1037,7 +1040,7 @@ void HeightmapMeshCreate ( HeightmapMeshVertexData **ppVertices, UInt16 **ppTria
// Generate heightmap mesh for one eye.
-void HeightmapMeshCreate( HeightmapMeshVertexData **ppVertices, UInt16 **ppTriangleListIndices,
+void HeightmapMeshCreate( HeightmapMeshVertexData **ppVertices, uint16_t **ppTriangleListIndices,
int *pNumVertices, int *pNumTriangles, bool rightEye,
const HmdRenderInfo &hmdRenderInfo,
const ScaleAndOffset2D &eyeToSourceNDC )
@@ -1046,7 +1049,7 @@ void HeightmapMeshCreate( HeightmapMeshVertexData **ppVertices, UInt16 **ppTrian
*pNumTriangles = HMA_NumTrisPerEye;
*ppVertices = (HeightmapMeshVertexData*) OVR_ALLOC( sizeof(HeightmapMeshVertexData) * (*pNumVertices) );
- *ppTriangleListIndices = (UInt16*) OVR_ALLOC( sizeof(UInt16) * (*pNumTriangles) * 3 );
+ *ppTriangleListIndices = (uint16_t*) OVR_ALLOC( sizeof(uint16_t) * (*pNumTriangles) * 3 );
if (!*ppVertices || !*ppTriangleListIndices)
{
@@ -1133,7 +1136,7 @@ void HeightmapMeshCreate( HeightmapMeshVertexData **ppVertices, UInt16 **ppTrian
// Populate index buffer info
- UInt16 *pcurIndex = *ppTriangleListIndices;
+ uint16_t *pcurIndex = *ppTriangleListIndices;
for ( int triNum = 0; triNum < HMA_GridSize * HMA_GridSize; triNum++ )
{
@@ -1180,23 +1183,23 @@ void HeightmapMeshCreate( HeightmapMeshVertexData **ppVertices, UInt16 **ppTrian
// so linear interpolation works better & we can use fewer tris.
if ( ( x < HMA_GridSize/2 ) != ( y < HMA_GridSize/2 ) ) // != is logical XOR
{
- *pcurIndex++ = (UInt16)FirstVertex;
- *pcurIndex++ = (UInt16)FirstVertex+1;
- *pcurIndex++ = (UInt16)FirstVertex+(HMA_GridSize+1)+1;
+ *pcurIndex++ = (uint16_t)FirstVertex;
+ *pcurIndex++ = (uint16_t)FirstVertex+1;
+ *pcurIndex++ = (uint16_t)FirstVertex+(HMA_GridSize+1)+1;
- *pcurIndex++ = (UInt16)FirstVertex+(HMA_GridSize+1)+1;
- *pcurIndex++ = (UInt16)FirstVertex+(HMA_GridSize+1);
- *pcurIndex++ = (UInt16)FirstVertex;
+ *pcurIndex++ = (uint16_t)FirstVertex+(HMA_GridSize+1)+1;
+ *pcurIndex++ = (uint16_t)FirstVertex+(HMA_GridSize+1);
+ *pcurIndex++ = (uint16_t)FirstVertex;
}
else
{
- *pcurIndex++ = (UInt16)FirstVertex;
- *pcurIndex++ = (UInt16)FirstVertex+1;
- *pcurIndex++ = (UInt16)FirstVertex+(HMA_GridSize+1);
+ *pcurIndex++ = (uint16_t)FirstVertex;
+ *pcurIndex++ = (uint16_t)FirstVertex+1;
+ *pcurIndex++ = (uint16_t)FirstVertex+(HMA_GridSize+1);
- *pcurIndex++ = (UInt16)FirstVertex+1;
- *pcurIndex++ = (UInt16)FirstVertex+(HMA_GridSize+1)+1;
- *pcurIndex++ = (UInt16)FirstVertex+(HMA_GridSize+1);
+ *pcurIndex++ = (uint16_t)FirstVertex+1;
+ *pcurIndex++ = (uint16_t)FirstVertex+(HMA_GridSize+1)+1;
+ *pcurIndex++ = (uint16_t)FirstVertex+(HMA_GridSize+1);
}
}
}
@@ -1318,7 +1321,7 @@ TimewarpMachine::TimewarpMachine()
{
for ( int i = 0; i < 2; i++ )
{
- EyeRenderPoses[i] = Transformf();
+ EyeRenderPoses[i] = Posef();
}
DistortionTimeCount = 0;
VsyncEnabled = false;
@@ -1349,10 +1352,9 @@ double TimewarpMachine::GetViewRenderPredictionTime()
return NextFramePresentFlushTime + CurrentPredictionValues.PresentFlushToRenderedScene;
}
-Transformf TimewarpMachine::GetViewRenderPredictionPose(SensorFusion &sfusion)
+bool TimewarpMachine::GetViewRenderPredictionPose(SensorStateReader* reader, Posef& pose)
{
- double predictionTime = GetViewRenderPredictionTime();
- return sfusion.GetPoseAtTime(predictionTime);
+ return reader->GetPoseAtTime(GetViewRenderPredictionTime(), pose);
}
double TimewarpMachine::GetVisiblePixelTimeStart()
@@ -1365,31 +1367,43 @@ double TimewarpMachine::GetVisiblePixelTimeEnd()
// Note that PredictionGetDeviceValues() did all the vsync-dependent thinking for us.
return NextFramePresentFlushTime + CurrentPredictionValues.PresentFlushToTimewarpEnd;
}
-Transformf TimewarpMachine::GetPredictedVisiblePixelPoseStart(SensorFusion &sfusion)
+bool TimewarpMachine::GetPredictedVisiblePixelPoseStart(SensorStateReader* reader, Posef& pose)
{
- double predictionTime = GetVisiblePixelTimeStart();
- return sfusion.GetPoseAtTime(predictionTime);
+ return reader->GetPoseAtTime(GetVisiblePixelTimeStart(), pose);
}
-Transformf TimewarpMachine::GetPredictedVisiblePixelPoseEnd (SensorFusion &sfusion)
+bool TimewarpMachine::GetPredictedVisiblePixelPoseEnd(SensorStateReader* reader, Posef& pose)
{
- double predictionTime = GetVisiblePixelTimeEnd();
- return sfusion.GetPoseAtTime(predictionTime);
+ return reader->GetPoseAtTime(GetVisiblePixelTimeEnd(), pose);
}
-Matrix4f TimewarpMachine::GetTimewarpDeltaStart(SensorFusion &sfusion, Transformf const &renderedPose)
+bool TimewarpMachine::GetTimewarpDeltaStart(SensorStateReader* reader, Posef const &renderedPose, Matrix4f& transform)
{
- Transformf visiblePose = GetPredictedVisiblePixelPoseStart ( sfusion );
+ Posef visiblePose;
+ if (!GetPredictedVisiblePixelPoseStart(reader, visiblePose))
+ {
+ return false;
+ }
+
Matrix4f visibleMatrix(visiblePose);
Matrix4f renderedMatrix(renderedPose);
Matrix4f identity; // doesn't matter for orientation-only timewarp
- return TimewarpComputePoseDelta ( renderedMatrix, visibleMatrix, identity );
+ transform = TimewarpComputePoseDelta ( renderedMatrix, visibleMatrix, identity );
+
+ return true;
}
-Matrix4f TimewarpMachine::GetTimewarpDeltaEnd (SensorFusion &sfusion, Transformf const &renderedPose)
+bool TimewarpMachine::GetTimewarpDeltaEnd(SensorStateReader* reader, Posef const &renderedPose, Matrix4f& transform)
{
- Transformf visiblePose = GetPredictedVisiblePixelPoseEnd ( sfusion );
+ Posef visiblePose;
+ if (!GetPredictedVisiblePixelPoseEnd(reader, visiblePose))
+ {
+ return false;
+ }
+
Matrix4f visibleMatrix(visiblePose);
Matrix4f renderedMatrix(renderedPose);
Matrix4f identity; // doesn't matter for orientation-only timewarp
- return TimewarpComputePoseDelta ( renderedMatrix, visibleMatrix, identity );
+ transform = TimewarpComputePoseDelta ( renderedMatrix, visibleMatrix, identity );
+
+ return true;
}
diff --git a/LibOVR/Src/Util/Util_Render_Stereo.h b/LibOVR/Src/Util/Util_Render_Stereo.h
index 326059e..2517c37 100644
--- a/LibOVR/Src/Util/Util_Render_Stereo.h
+++ b/LibOVR/Src/Util/Util_Render_Stereo.h
@@ -1,6 +1,5 @@
/************************************************************************************
-PublicHeader: OVR.h
Filename : Util_Render_Stereo.h
Content : Sample stereo rendering configuration classes.
Created : October 22, 2012
@@ -29,13 +28,9 @@ limitations under the License.
#define OVR_Util_Render_Stereo_h
#include "../OVR_Stereo.h"
+#include "../Tracking/Tracking_SensorStateReader.h"
-
-namespace OVR {
-
-class SensorFusion;
-
-namespace Util { namespace Render {
+namespace OVR { namespace Util { namespace Render {
@@ -334,19 +329,19 @@ struct DistortionMeshVertexData
};
-void DistortionMeshCreate ( DistortionMeshVertexData **ppVertices, UInt16 **ppTriangleListIndices,
+void DistortionMeshCreate ( DistortionMeshVertexData **ppVertices, uint16_t **ppTriangleListIndices,
int *pNumVertices, int *pNumTriangles,
const StereoEyeParams &stereoParams, const HmdRenderInfo &hmdRenderInfo );
// Generate distortion mesh for a eye. This version requires less data then stereoParms, supporting
// dynamic change in render target viewport.
-void DistortionMeshCreate( DistortionMeshVertexData **ppVertices, UInt16 **ppTriangleListIndices,
+void DistortionMeshCreate( DistortionMeshVertexData **ppVertices, uint16_t **ppTriangleListIndices,
int *pNumVertices, int *pNumTriangles,
bool rightEye,
const HmdRenderInfo &hmdRenderInfo,
const DistortionRenderDesc &distortion, const ScaleAndOffset2D &eyeToSourceNDC );
-void DistortionMeshDestroy ( DistortionMeshVertexData *pVertices, UInt16 *pTriangleMeshIndices );
+void DistortionMeshDestroy ( DistortionMeshVertexData *pVertices, uint16_t *pTriangleMeshIndices );
//-----------------------------------------------------------------------------------
@@ -368,17 +363,17 @@ struct HeightmapMeshVertexData
};
-void HeightmapMeshCreate ( HeightmapMeshVertexData **ppVertices, UInt16 **ppTriangleListIndices,
+void HeightmapMeshCreate ( HeightmapMeshVertexData **ppVertices, uint16_t **ppTriangleListIndices,
int *pNumVertices, int *pNumTriangles,
const StereoEyeParams &stereoParams, const HmdRenderInfo &hmdRenderInfo );
// Generate heightmap mesh for a eye. This version requires less data then stereoParms, supporting
// dynamic change in render target viewport.
-void HeightmapMeshCreate( HeightmapMeshVertexData **ppVertices, UInt16 **ppTriangleListIndices,
+void HeightmapMeshCreate( HeightmapMeshVertexData **ppVertices, uint16_t **ppTriangleListIndices,
int *pNumVertices, int *pNumTriangles, bool rightEye,
const HmdRenderInfo &hmdRenderInfo, const ScaleAndOffset2D &eyeToSourceNDC );
-void HeightmapMeshDestroy ( HeightmapMeshVertexData *pVertices, UInt16 *pTriangleMeshIndices );
+void HeightmapMeshDestroy ( HeightmapMeshVertexData *pVertices, uint16_t *pTriangleMeshIndices );
@@ -434,7 +429,7 @@ public:
// and the predicted pose of the HMD at that time.
// You usually only need to call one of these functions.
double GetViewRenderPredictionTime();
- Transformf GetViewRenderPredictionPose(SensorFusion &sfusion);
+ bool GetViewRenderPredictionPose(Tracking::SensorStateReader* reader, Posef& transform);
// Timewarp prediction functions. You usually only need to call one of these three sets of functions.
@@ -443,14 +438,13 @@ public:
double GetVisiblePixelTimeStart();
double GetVisiblePixelTimeEnd();
// Predicted poses of the HMD at those first and last pixels.
- Transformf GetPredictedVisiblePixelPoseStart(SensorFusion &sfusion);
- Transformf GetPredictedVisiblePixelPoseEnd (SensorFusion &sfusion);
+ bool GetPredictedVisiblePixelPoseStart(Tracking::SensorStateReader* reader, Posef& transform);
+ bool GetPredictedVisiblePixelPoseEnd(Tracking::SensorStateReader* reader, Posef& transform);
// The delta matrices to feed to the timewarp distortion code,
// given the pose that was used for rendering.
// (usually the one returned by GetViewRenderPredictionPose() earlier)
- Matrix4f GetTimewarpDeltaStart(SensorFusion &sfusion, Transformf const &renderedPose);
- Matrix4f GetTimewarpDeltaEnd (SensorFusion &sfusion, Transformf const &renderedPose);
-
+ bool GetTimewarpDeltaStart(Tracking::SensorStateReader* reader, Posef const &renderedPose, Matrix4f& transform);
+ bool GetTimewarpDeltaEnd(Tracking::SensorStateReader* reader, Posef const &renderedPose, Matrix4f& transform);
// Just-In-Time distortion aims to delay the second sensor reading & distortion
// until the very last moment to improve prediction. However, it is a little scary,
@@ -466,9 +460,7 @@ public:
void JustInTime_BeforeDistortionTimeMeasurement(double timeNow);
void JustInTime_AfterDistortionTimeMeasurement(double timeNow);
-
private:
-
bool VsyncEnabled;
HmdRenderInfo RenderInfo;
PredictionValues CurrentPredictionValues;
@@ -480,11 +472,11 @@ private:
float DistortionTimeAverage;
// Pose at which last time the eye was rendered.
- Transformf EyeRenderPoses[2];
+ Posef EyeRenderPoses[2];
// Absolute time of the last present+flush
double LastFramePresentFlushTime;
- // Seconds between presentflushes
+ // Seconds between present+flushes
float PresentFlushToPresentFlushSeconds;
// Predicted absolute time of the next present+flush
double NextFramePresentFlushTime;
diff --git a/LibOVR/Src/Util/Util_Settings.cpp b/LibOVR/Src/Util/Util_Settings.cpp
new file mode 100644
index 0000000..d7b3f0d
--- /dev/null
+++ b/LibOVR/Src/Util/Util_Settings.cpp
@@ -0,0 +1,312 @@
+/************************************************************************************
+
+Filename : Util_Settings.cpp
+Content : Persistent settings subsystem
+Created : June 11, 2014
+Author : Chris Taylor
+
+Copyright : Copyright 2014 Oculus VR, Inc. All Rights reserved.
+
+Licensed under the Oculus VR Rift SDK License Version 3.1 (the "License");
+you may not use the Oculus VR Rift SDK except in compliance with the License,
+which is provided at the time of installation or download, or which
+otherwise accompanies this software in either electronic or hard copy form.
+
+You may obtain a copy of the License at
+
+http://www.oculusvr.com/licenses/LICENSE-3.1
+
+Unless required by applicable law or agreed to in writing, the Oculus VR SDK
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+************************************************************************************/
+
+#include "Util_Settings.h"
+#include "../OVR_Profile.h"
+
+OVR_DEFINE_SINGLETON(Util::Settings);
+
+namespace OVR { namespace Util {
+
+
+//// Settings
+
+Settings::Settings() :
+ Dirty(false)
+{
+ // Set up long poll handler
+ PollObserver.SetHandler(LongPollThread::PollFunc::FromMember<Settings, &Settings::pollDirty>(this));
+ LongPollThread::GetInstance()->AddPollFunc(PollObserver);
+
+ PushDestroyCallbacks();
+}
+
+Settings::~Settings()
+{
+ PollObserver.ReleaseAll();
+
+ Lock::Locker locker(&DataLock);
+
+ if (Dirty)
+ {
+ updateFile();
+ Dirty = false;
+ }
+}
+
+void Settings::OnSystemDestroy()
+{
+ delete this;
+}
+
+void Settings::SetFileName(const String& fileName)
+{
+ Lock::Locker locker(&DataLock);
+
+ OVR_ASSERT(FullFilePath.IsEmpty());
+
+ if (FullFilePath.IsEmpty())
+ {
+ FullFilePath = GetBaseOVRPath(true) + "/" + fileName;
+
+ loadFile();
+ }
+}
+
+void Settings::loadFile()
+{
+ Root = *JSON::Load(FullFilePath.ToCStr());
+ if (!Root)
+ {
+ OVR_DEBUG_LOG(("[Settings] Settings file was empty"));
+ }
+ else
+ {
+ OVR_DEBUG_LOG(("[Settings] Successfully read settings file"));
+ }
+}
+
+void Settings::updateFile()
+{
+ OVR_ASSERT(!FullFilePath.IsEmpty());
+
+ if (Root->Save(FullFilePath.ToCStr()))
+ {
+ OVR_DEBUG_LOG(("[Settings] Updated settings file: %s", FullFilePath.ToCStr()));
+ Dirty = false;
+ }
+ else
+ {
+ LogError("[Settings] WARNING: Unable to write settings file: %s", FullFilePath.ToCStr());
+ OVR_ASSERT(false);
+ }
+}
+
+void Settings::pollDirty()
+{
+ // If dirty,
+ if (Dirty)
+ {
+ Lock::Locker locker(&DataLock);
+
+ if (!Dirty)
+ {
+ return;
+ }
+
+ updateFile();
+ }
+}
+
+void Settings::SetNumber(const char* key, double value)
+{
+ Lock::Locker locker(&DataLock);
+
+ Dirty = true;
+
+ if (!Root)
+ {
+ Root = *JSON::CreateObject();
+ }
+
+ Ptr<JSON> item = Root->GetItemByName(key);
+ if (!item)
+ {
+ Root->AddNumberItem(key, value);
+ return;
+ }
+
+ item->Type = JSON_Number;
+ item->dValue = value;
+}
+
+void Settings::SetInt(const char* key, int value)
+{
+ Lock::Locker locker(&DataLock);
+
+ if (!Root)
+ {
+ Root = *JSON::CreateObject();
+ Dirty = true;
+ }
+
+ Ptr<JSON> item = Root->GetItemByName(key);
+ if (!item)
+ {
+ Root->AddIntItem(key, value);
+ Dirty = true;
+ return;
+ }
+
+ // If the value changed,
+ if (item->Type != JSON_Number ||
+ (int)item->dValue != value)
+ {
+ item->Type = JSON_Number;
+ item->dValue = value;
+ Dirty = true;
+ }
+}
+
+void Settings::SetBool(const char* key, bool value)
+{
+ Lock::Locker locker(&DataLock);
+
+ if (!Root)
+ {
+ Root = *JSON::CreateObject();
+ Dirty = true;
+ }
+
+ Ptr<JSON> item = Root->GetItemByName(key);
+ if (!item)
+ {
+ Root->AddBoolItem(key, value);
+ Dirty = true;
+ return;
+ }
+
+ // If the value changed,
+ if (item->Type != JSON_Bool ||
+ ((int)item->dValue != 0) != value)
+ {
+ item->Type = JSON_Bool;
+ item->dValue = value ? 1. : 0.;
+ item->Value = value ? "true" : "false";
+ Dirty = true;
+ }
+}
+
+void Settings::SetString(const char* key, const char* value)
+{
+ Lock::Locker locker(&DataLock);
+
+ if (!Root)
+ {
+ Root = *JSON::CreateObject();
+ Dirty = true;
+ }
+
+ Ptr<JSON> item = Root->GetItemByName(key);
+ if (!item)
+ {
+ Root->AddStringItem(key, value);
+ Dirty = true;
+ return;
+ }
+
+ // If the value changed,
+ if (item->Type != JSON_String ||
+ item->Value != value)
+ {
+ item->Type = JSON_String;
+ item->Value = value;
+ Dirty = true;
+ }
+}
+
+double Settings::GetNumber(const char* key, double defaultValue)
+{
+ Lock::Locker locker(&DataLock);
+
+ if (!Root)
+ {
+ SetNumber(key, defaultValue);
+ return defaultValue;
+ }
+
+ Ptr<JSON> item = Root->GetItemByName(key);
+ if (!item)
+ {
+ SetNumber(key, defaultValue);
+ return defaultValue;
+ }
+
+ return item->dValue;
+}
+
+int Settings::GetInt(const char* key, int defaultValue)
+{
+ Lock::Locker locker(&DataLock);
+
+ if (!Root)
+ {
+ SetInt(key, defaultValue);
+ return defaultValue;
+ }
+
+ Ptr<JSON> item = Root->GetItemByName(key);
+ if (!item)
+ {
+ SetInt(key, defaultValue);
+ return defaultValue;
+ }
+
+ return (int)item->dValue;
+}
+
+bool Settings::GetBool(const char* key, bool defaultValue)
+{
+ Lock::Locker locker(&DataLock);
+
+ if (!Root)
+ {
+ SetBool(key, defaultValue);
+ return defaultValue;
+ }
+
+ Ptr<JSON> item = Root->GetItemByName(key);
+ if (!item)
+ {
+ SetBool(key, defaultValue);
+ return defaultValue;
+ }
+
+ return (int)item->dValue != 0;
+}
+
+String Settings::GetString(const char* key, const char* defaultValue)
+{
+ Lock::Locker locker(&DataLock);
+
+ if (!Root)
+ {
+ SetString(key, defaultValue);
+ return defaultValue;
+ }
+
+ Ptr<JSON> item = Root->GetItemByName(key);
+ if (!item)
+ {
+ SetString(key, defaultValue);
+ return defaultValue;
+ }
+
+ return item->Value;
+}
+
+
+}} // namespace OVR::Util
diff --git a/LibOVR/Src/Util/Util_Settings.h b/LibOVR/Src/Util/Util_Settings.h
new file mode 100644
index 0000000..79ea172
--- /dev/null
+++ b/LibOVR/Src/Util/Util_Settings.h
@@ -0,0 +1,83 @@
+/************************************************************************************
+
+PublicHeader: n/a
+Filename : Util_Settings.h
+Content : Persistent settings subsystem
+Created : June 11, 2014
+Author : Chris Taylor
+
+Copyright : Copyright 2014 Oculus VR, Inc. All Rights reserved.
+
+Licensed under the Oculus VR Rift SDK License Version 3.1 (the "License");
+you may not use the Oculus VR Rift SDK except in compliance with the License,
+which is provided at the time of installation or download, or which
+otherwise accompanies this software in either electronic or hard copy form.
+
+You may obtain a copy of the License at
+
+http://www.oculusvr.com/licenses/LICENSE-3.1
+
+Unless required by applicable law or agreed to in writing, the Oculus VR SDK
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+************************************************************************************/
+
+#ifndef OVR_Settings_h
+#define OVR_Settings_h
+
+#include "../Kernel/OVR_String.h"
+#include "../Kernel/OVR_System.h"
+#include "../Kernel/OVR_Observer.h"
+#include "../OVR_JSON.h"
+#include "Util_LongPollThread.h"
+
+namespace OVR { namespace Util {
+
+
+//-----------------------------------------------------------------------------
+// Settings
+
+class Settings : public NewOverrideBase, public SystemSingletonBase<Settings>
+{
+ OVR_DECLARE_SINGLETON(Settings);
+
+ ObserverScope<LongPollThread::PollFunc> PollObserver;
+ void pollDirty();
+
+ // Helpers (call with lock held)
+ void loadFile();
+ void updateFile();
+
+ // Synchronization for data access
+ Lock DataLock;
+
+ // Full path to the JSON settings file
+ String FullFilePath;
+
+ // Backed by JSON
+ Ptr<JSON> Root;
+
+ // Dirty flag to capture multiple changes for long poll writes
+ bool Dirty;
+
+public:
+ void SetFileName(const String& fileName);
+
+ void SetNumber(const char* key, double value);
+ void SetInt(const char* key, int value);
+ void SetBool(const char* key, bool value);
+ void SetString(const char* key, const char* value);
+
+ double GetNumber(const char* key, double defaultValue = 0.);
+ int GetInt(const char* key, int defaultValue = 0);
+ bool GetBool(const char* key, bool defaultValue = false);
+ String GetString(const char* key, const char* defaultValue = "");
+};
+
+
+}} // namespace OVR::Util
+
+#endif // OVR_Settings_h