rev |
line source |
nuclear@0
|
1 /************************************************************************************
|
nuclear@0
|
2
|
nuclear@0
|
3 Filename : CAPI_HMDState.cpp
|
nuclear@0
|
4 Content : State associated with a single HMD
|
nuclear@0
|
5 Created : January 24, 2014
|
nuclear@0
|
6 Authors : Michael Antonov
|
nuclear@0
|
7
|
nuclear@0
|
8 Copyright : Copyright 2014 Oculus VR, LLC All Rights reserved.
|
nuclear@0
|
9
|
nuclear@0
|
10 Licensed under the Oculus VR Rift SDK License Version 3.2 (the "License");
|
nuclear@0
|
11 you may not use the Oculus VR Rift SDK except in compliance with the License,
|
nuclear@0
|
12 which is provided at the time of installation or download, or which
|
nuclear@0
|
13 otherwise accompanies this software in either electronic or hard copy form.
|
nuclear@0
|
14
|
nuclear@0
|
15 You may obtain a copy of the License at
|
nuclear@0
|
16
|
nuclear@0
|
17 http://www.oculusvr.com/licenses/LICENSE-3.2
|
nuclear@0
|
18
|
nuclear@0
|
19 Unless required by applicable law or agreed to in writing, the Oculus VR SDK
|
nuclear@0
|
20 distributed under the License is distributed on an "AS IS" BASIS,
|
nuclear@0
|
21 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
nuclear@0
|
22 See the License for the specific language governing permissions and
|
nuclear@0
|
23 limitations under the License.
|
nuclear@0
|
24
|
nuclear@0
|
25 ************************************************************************************/
|
nuclear@0
|
26
|
nuclear@0
|
27 #include "CAPI_HMDState.h"
|
nuclear@0
|
28 #include "../OVR_Profile.h"
|
nuclear@0
|
29 #include "../Service/Service_NetClient.h"
|
nuclear@0
|
30 #ifdef OVR_OS_WIN32
|
nuclear@0
|
31 #include "../Displays/OVR_Win32_ShimFunctions.h"
|
nuclear@0
|
32 #endif
|
nuclear@0
|
33
|
nuclear@0
|
34
|
nuclear@0
|
35 namespace OVR { namespace CAPI {
|
nuclear@0
|
36
|
nuclear@0
|
37
|
nuclear@0
|
38 // Accessed via HMDState::GetHMDStateList()
|
nuclear@0
|
39 static OVR::List<HMDState> hmdStateList; // List of all created HMDStates.
|
nuclear@0
|
40
|
nuclear@0
|
41
|
nuclear@0
|
42 //-------------------------------------------------------------------------------------
|
nuclear@0
|
43 // ***** HMDState
|
nuclear@0
|
44
|
nuclear@0
|
45 HMDState::HMDState(const OVR::Service::HMDNetworkInfo& netInfo,
|
nuclear@0
|
46 const OVR::HMDInfo& hmdInfo,
|
nuclear@0
|
47 Profile* profile,
|
nuclear@0
|
48 Service::NetClient* client) :
|
nuclear@0
|
49 pProfile(profile),
|
nuclear@0
|
50 pHmdDesc(0),
|
nuclear@0
|
51 pWindow(0),
|
nuclear@0
|
52 pClient(client),
|
nuclear@0
|
53 NetId(netInfo.NetId),
|
nuclear@0
|
54 NetInfo(netInfo),
|
nuclear@0
|
55 OurHMDInfo(hmdInfo),
|
nuclear@0
|
56 pLastError(NULL),
|
nuclear@0
|
57 EnabledHmdCaps(0),
|
nuclear@0
|
58 EnabledServiceHmdCaps(0),
|
nuclear@0
|
59 SharedStateReader(),
|
nuclear@0
|
60 TheSensorStateReader(),
|
nuclear@0
|
61 TheLatencyTestStateReader(),
|
nuclear@0
|
62 LatencyTestActive(false),
|
nuclear@0
|
63 //LatencyTestDrawColor(),
|
nuclear@0
|
64 LatencyTest2Active(false),
|
nuclear@0
|
65 //LatencyTest2DrawColor(),
|
nuclear@0
|
66 TimeManager(true),
|
nuclear@0
|
67 RenderState(),
|
nuclear@0
|
68 pRenderer(),
|
nuclear@0
|
69 pHSWDisplay(),
|
nuclear@0
|
70 LastFrameTimeSeconds(0.),
|
nuclear@0
|
71 LastGetFrameTimeSeconds(0.),
|
nuclear@0
|
72 //LastGetStringValue(),
|
nuclear@0
|
73 RenderingConfigured(false),
|
nuclear@0
|
74 BeginFrameCalled(false),
|
nuclear@0
|
75 BeginFrameThreadId(),
|
nuclear@0
|
76 RenderAPIThreadChecker(),
|
nuclear@0
|
77 BeginFrameTimingCalled(false)
|
nuclear@0
|
78 {
|
nuclear@0
|
79 sharedInit(profile);
|
nuclear@0
|
80 hmdStateList.PushBack(this);
|
nuclear@0
|
81 }
|
nuclear@0
|
82
|
nuclear@0
|
83
|
nuclear@0
|
84 HMDState::HMDState(const OVR::HMDInfo& hmdInfo, Profile* profile) :
|
nuclear@0
|
85 pProfile(profile),
|
nuclear@0
|
86 pHmdDesc(0),
|
nuclear@0
|
87 pWindow(0),
|
nuclear@0
|
88 pClient(0),
|
nuclear@0
|
89 NetId(InvalidVirtualHmdId),
|
nuclear@0
|
90 NetInfo(),
|
nuclear@0
|
91 OurHMDInfo(hmdInfo),
|
nuclear@0
|
92 pLastError(NULL),
|
nuclear@0
|
93 EnabledHmdCaps(0),
|
nuclear@0
|
94 EnabledServiceHmdCaps(0),
|
nuclear@0
|
95 SharedStateReader(),
|
nuclear@0
|
96 TheSensorStateReader(),
|
nuclear@0
|
97 TheLatencyTestStateReader(),
|
nuclear@0
|
98 LatencyTestActive(false),
|
nuclear@0
|
99 //LatencyTestDrawColor(),
|
nuclear@0
|
100 LatencyTest2Active(false),
|
nuclear@0
|
101 //LatencyTest2DrawColor(),
|
nuclear@0
|
102 TimeManager(true),
|
nuclear@0
|
103 RenderState(),
|
nuclear@0
|
104 pRenderer(),
|
nuclear@0
|
105 pHSWDisplay(),
|
nuclear@0
|
106 LastFrameTimeSeconds(0.),
|
nuclear@0
|
107 LastGetFrameTimeSeconds(0.),
|
nuclear@0
|
108 //LastGetStringValue(),
|
nuclear@0
|
109 RenderingConfigured(false),
|
nuclear@0
|
110 BeginFrameCalled(false),
|
nuclear@0
|
111 BeginFrameThreadId(),
|
nuclear@0
|
112 RenderAPIThreadChecker(),
|
nuclear@0
|
113 BeginFrameTimingCalled(false)
|
nuclear@0
|
114 {
|
nuclear@0
|
115 sharedInit(profile);
|
nuclear@0
|
116 hmdStateList.PushBack(this);
|
nuclear@0
|
117 }
|
nuclear@0
|
118
|
nuclear@0
|
119 HMDState::~HMDState()
|
nuclear@0
|
120 {
|
nuclear@0
|
121 hmdStateList.Remove(this);
|
nuclear@0
|
122
|
nuclear@0
|
123 if (pClient)
|
nuclear@0
|
124 {
|
nuclear@0
|
125 pClient->Hmd_Release(NetId);
|
nuclear@0
|
126 pClient = 0;
|
nuclear@0
|
127 }
|
nuclear@0
|
128
|
nuclear@0
|
129 ConfigureRendering(0,0,0,0);
|
nuclear@0
|
130
|
nuclear@0
|
131 if (pHmdDesc)
|
nuclear@0
|
132 {
|
nuclear@0
|
133 OVR_FREE(pHmdDesc);
|
nuclear@0
|
134 pHmdDesc = NULL;
|
nuclear@0
|
135 }
|
nuclear@0
|
136 }
|
nuclear@0
|
137
|
nuclear@0
|
138 void HMDState::sharedInit(Profile* profile)
|
nuclear@0
|
139 {
|
nuclear@0
|
140 // TBD: We should probably be looking up the default profile for the given
|
nuclear@0
|
141 // device type + user if profile == 0.
|
nuclear@0
|
142 pLastError = 0;
|
nuclear@0
|
143
|
nuclear@0
|
144 RenderState.OurHMDInfo = OurHMDInfo;
|
nuclear@0
|
145
|
nuclear@0
|
146 UpdateRenderProfile(profile);
|
nuclear@0
|
147
|
nuclear@0
|
148 OVR_ASSERT(!pHmdDesc);
|
nuclear@0
|
149 pHmdDesc = (ovrHmdDesc*)OVR_ALLOC(sizeof(ovrHmdDesc));
|
nuclear@0
|
150 *pHmdDesc = RenderState.GetDesc();
|
nuclear@0
|
151 pHmdDesc->Handle = this;
|
nuclear@0
|
152
|
nuclear@0
|
153 RenderState.ClearColor[0] = 0.0f;
|
nuclear@0
|
154 RenderState.ClearColor[1] = 0.0f;
|
nuclear@0
|
155 RenderState.ClearColor[2] = 0.0f;
|
nuclear@0
|
156 RenderState.ClearColor[3] = 0.0f;
|
nuclear@0
|
157
|
nuclear@0
|
158 RenderState.EnabledHmdCaps = 0;
|
nuclear@0
|
159
|
nuclear@0
|
160 TimeManager.Init(RenderState.RenderInfo);
|
nuclear@0
|
161
|
nuclear@0
|
162 /*
|
nuclear@0
|
163 LatencyTestDrawColor[0] = 0;
|
nuclear@0
|
164 LatencyTestDrawColor[1] = 0;
|
nuclear@0
|
165 LatencyTestDrawColor[2] = 0;
|
nuclear@0
|
166 */
|
nuclear@0
|
167
|
nuclear@0
|
168 RenderingConfigured = false;
|
nuclear@0
|
169 BeginFrameCalled = false;
|
nuclear@0
|
170 BeginFrameThreadId = 0;
|
nuclear@0
|
171 BeginFrameTimingCalled = false;
|
nuclear@0
|
172
|
nuclear@0
|
173 // Construct the HSWDisplay. We will later reconstruct it with a specific ovrRenderAPI type if the application starts using SDK-based rendering.
|
nuclear@0
|
174 if(!pHSWDisplay)
|
nuclear@0
|
175 {
|
nuclear@0
|
176 pHSWDisplay = *OVR::CAPI::HSWDisplay::Factory(ovrRenderAPI_None, pHmdDesc, RenderState);
|
nuclear@0
|
177 pHSWDisplay->Enable(pProfile->GetBoolValue("HSW", true));
|
nuclear@0
|
178 }
|
nuclear@0
|
179 }
|
nuclear@0
|
180
|
nuclear@0
|
181 static Vector3f GetNeckModelFromProfile(Profile* profile)
|
nuclear@0
|
182 {
|
nuclear@0
|
183 OVR_ASSERT(profile);
|
nuclear@0
|
184
|
nuclear@0
|
185 float neckeye[2] = { OVR_DEFAULT_NECK_TO_EYE_HORIZONTAL, OVR_DEFAULT_NECK_TO_EYE_VERTICAL };
|
nuclear@0
|
186 profile->GetFloatValues(OVR_KEY_NECK_TO_EYE_DISTANCE, neckeye, 2);
|
nuclear@0
|
187
|
nuclear@0
|
188 // Make sure these are vaguely sensible values.
|
nuclear@0
|
189 //OVR_ASSERT((neckeye[0] > 0.05f) && (neckeye[0] < 0.5f));
|
nuclear@0
|
190 //OVR_ASSERT((neckeye[1] > 0.05f) && (neckeye[1] < 0.5f));
|
nuclear@0
|
191
|
nuclear@0
|
192 // Named for clarity
|
nuclear@0
|
193 float NeckToEyeHorizontal = neckeye[0];
|
nuclear@0
|
194 float NeckToEyeVertical = neckeye[1];
|
nuclear@0
|
195
|
nuclear@0
|
196 // Store the neck model
|
nuclear@0
|
197 return Vector3f(0.0, NeckToEyeVertical, -NeckToEyeHorizontal);
|
nuclear@0
|
198 }
|
nuclear@0
|
199
|
nuclear@0
|
200 static float GetCenterPupilDepthFromRenderInfo(HmdRenderInfo* hmdRenderInfo)
|
nuclear@0
|
201 {
|
nuclear@0
|
202 OVR_ASSERT(hmdRenderInfo);
|
nuclear@0
|
203
|
nuclear@0
|
204 // Find the distance from the center of the screen to the "center eye"
|
nuclear@0
|
205 // This center eye is used by systems like rendering & audio to represent the player,
|
nuclear@0
|
206 // and they will handle the offsets needed from there to each actual eye.
|
nuclear@0
|
207
|
nuclear@0
|
208 // HACK HACK HACK
|
nuclear@0
|
209 // We know for DK1 the screen->lens surface distance is roughly 0.049f, and that the faceplate->lens is 0.02357f.
|
nuclear@0
|
210 // We're going to assume(!!!!) that all HMDs have the same screen->faceplate distance.
|
nuclear@0
|
211 // Crystal Cove was measured to be roughly 0.025 screen->faceplate which agrees with this assumption.
|
nuclear@0
|
212 // TODO: do this properly! Update: Measured this at 0.02733 with a CC prototype, CES era (PT7), on 2/19/14 -Steve
|
nuclear@0
|
213 float screenCenterToMidplate = 0.02733f;
|
nuclear@0
|
214 float centerEyeRelief = hmdRenderInfo->GetEyeCenter().ReliefInMeters;
|
nuclear@0
|
215 float CenterPupilDepth = screenCenterToMidplate + hmdRenderInfo->LensSurfaceToMidplateInMeters + centerEyeRelief;
|
nuclear@0
|
216
|
nuclear@0
|
217 return CenterPupilDepth;
|
nuclear@0
|
218 }
|
nuclear@0
|
219
|
nuclear@0
|
220 void HMDState::UpdateRenderProfile(Profile* profile)
|
nuclear@0
|
221 {
|
nuclear@0
|
222 // Apply the given profile to generate a render context
|
nuclear@0
|
223 RenderState.RenderInfo = GenerateHmdRenderInfoFromHmdInfo(RenderState.OurHMDInfo, profile);
|
nuclear@0
|
224 RenderState.Distortion[0] = CalculateDistortionRenderDesc(StereoEye_Left, RenderState.RenderInfo, 0);
|
nuclear@0
|
225 RenderState.Distortion[1] = CalculateDistortionRenderDesc(StereoEye_Right, RenderState.RenderInfo, 0);
|
nuclear@0
|
226
|
nuclear@0
|
227 if (pClient)
|
nuclear@0
|
228 {
|
nuclear@0
|
229 // Center pupil depth
|
nuclear@0
|
230 float centerPupilDepth = GetCenterPupilDepthFromRenderInfo(&RenderState.RenderInfo);
|
nuclear@0
|
231 pClient->SetNumberValue(GetNetId(), "CenterPupilDepth", centerPupilDepth);
|
nuclear@0
|
232
|
nuclear@0
|
233 // Neck model
|
nuclear@0
|
234 Vector3f neckModel = GetNeckModelFromProfile(profile);
|
nuclear@0
|
235 double neckModelArray[3] = {
|
nuclear@0
|
236 neckModel.x,
|
nuclear@0
|
237 neckModel.y,
|
nuclear@0
|
238 neckModel.z
|
nuclear@0
|
239 };
|
nuclear@0
|
240 pClient->SetNumberValues(GetNetId(), "NeckModelVector3f", neckModelArray, 3);
|
nuclear@0
|
241
|
nuclear@0
|
242 double camerastate[7];
|
nuclear@0
|
243 if (profile->GetDoubleValues(OVR_KEY_CAMERA_POSITION, camerastate, 7) == 0)
|
nuclear@0
|
244 {
|
nuclear@0
|
245 //there is no value, so we load the default
|
nuclear@0
|
246 for (int i = 0; i < 7; i++) camerastate[i] = 0;
|
nuclear@0
|
247 camerastate[3] = 1;//no offset. by default, give the quaternion w component value 1
|
nuclear@0
|
248 }
|
nuclear@0
|
249 else
|
nuclear@0
|
250
|
nuclear@0
|
251 TheSensorStateReader.setCenteredFromWorld(OVR::Posed::FromArray(camerastate));
|
nuclear@0
|
252 }
|
nuclear@0
|
253
|
nuclear@0
|
254
|
nuclear@0
|
255 }
|
nuclear@0
|
256
|
nuclear@0
|
257 HMDState* HMDState::CreateHMDState(NetClient* client, const HMDNetworkInfo& netInfo)
|
nuclear@0
|
258 {
|
nuclear@0
|
259 // HMDState works through a handle to service HMD....
|
nuclear@0
|
260 HMDInfo hinfo;
|
nuclear@0
|
261 if (!client->Hmd_GetHmdInfo(netInfo.NetId, &hinfo))
|
nuclear@0
|
262 {
|
nuclear@0
|
263 OVR_DEBUG_LOG(("[HMDState] Unable to get HMD info"));
|
nuclear@0
|
264 return NULL;
|
nuclear@0
|
265 }
|
nuclear@0
|
266
|
nuclear@0
|
267 #ifdef OVR_OS_WIN32
|
nuclear@0
|
268 OVR_DEBUG_LOG(("Setting up display shim"));
|
nuclear@0
|
269
|
nuclear@0
|
270 // Initialize the display shim before reporting the display to the user code
|
nuclear@0
|
271 // so that this will happen before the D3D display object is created.
|
nuclear@0
|
272 Win32::DisplayShim::GetInstance().Update(&hinfo.ShimInfo);
|
nuclear@0
|
273 #endif
|
nuclear@0
|
274
|
nuclear@0
|
275 Ptr<Profile> pDefaultProfile = *ProfileManager::GetInstance()->GetDefaultUserProfile(&hinfo);
|
nuclear@0
|
276 OVR_DEBUG_LOG(("Using profile %s", pDefaultProfile->GetValue(OVR_KEY_USER)));
|
nuclear@0
|
277
|
nuclear@0
|
278 HMDState* hmds = new HMDState(netInfo, hinfo, pDefaultProfile, client);
|
nuclear@0
|
279
|
nuclear@0
|
280 if (!hmds->SharedStateReader.Open(netInfo.SharedMemoryName.ToCStr()))
|
nuclear@0
|
281 {
|
nuclear@0
|
282 delete hmds;
|
nuclear@0
|
283 return NULL;
|
nuclear@0
|
284 }
|
nuclear@0
|
285
|
nuclear@0
|
286 hmds->TheSensorStateReader.SetUpdater(hmds->SharedStateReader.Get());
|
nuclear@0
|
287 hmds->TheLatencyTestStateReader.SetUpdater(hmds->SharedStateReader.Get());
|
nuclear@0
|
288
|
nuclear@0
|
289 return hmds;
|
nuclear@0
|
290 }
|
nuclear@0
|
291
|
nuclear@0
|
292 HMDState* HMDState::CreateHMDState(ovrHmdType hmdType)
|
nuclear@0
|
293 {
|
nuclear@0
|
294 HmdTypeEnum t = HmdType_None;
|
nuclear@0
|
295 if (hmdType == ovrHmd_DK1)
|
nuclear@0
|
296 t = HmdType_DK1;
|
nuclear@0
|
297 else if (hmdType == ovrHmd_DK2)
|
nuclear@0
|
298 t = HmdType_DK2;
|
nuclear@0
|
299
|
nuclear@0
|
300 // FIXME: This does not actually grab the right user..
|
nuclear@0
|
301 Ptr<Profile> pDefaultProfile = *ProfileManager::GetInstance()->GetDefaultProfile(t);
|
nuclear@0
|
302
|
nuclear@0
|
303 return new HMDState(CreateDebugHMDInfo(t), pDefaultProfile);
|
nuclear@0
|
304 }
|
nuclear@0
|
305
|
nuclear@0
|
306
|
nuclear@0
|
307 const OVR::List<HMDState>& HMDState::GetHMDStateList()
|
nuclear@0
|
308 {
|
nuclear@0
|
309 return hmdStateList;
|
nuclear@0
|
310 }
|
nuclear@0
|
311
|
nuclear@0
|
312
|
nuclear@0
|
313 //-------------------------------------------------------------------------------------
|
nuclear@0
|
314 // *** Sensor
|
nuclear@0
|
315
|
nuclear@0
|
316 bool HMDState::ConfigureTracking(unsigned supportedCaps, unsigned requiredCaps)
|
nuclear@0
|
317 {
|
nuclear@0
|
318 return pClient ? pClient->Hmd_ConfigureTracking(NetId, supportedCaps, requiredCaps) : true;
|
nuclear@0
|
319 }
|
nuclear@0
|
320
|
nuclear@0
|
321 void HMDState::ResetTracking()
|
nuclear@0
|
322 {
|
nuclear@0
|
323 if (pClient) pClient->Hmd_ResetTracking(NetId);
|
nuclear@0
|
324 }
|
nuclear@0
|
325
|
nuclear@0
|
326 // Re-center the orientation.
|
nuclear@0
|
327 void HMDState::RecenterPose()
|
nuclear@0
|
328 {
|
nuclear@0
|
329 TheSensorStateReader.RecenterPose();
|
nuclear@0
|
330 }
|
nuclear@0
|
331
|
nuclear@0
|
332 // Returns prediction for time.
|
nuclear@0
|
333 ovrTrackingState HMDState::PredictedTrackingState(double absTime)
|
nuclear@0
|
334 {
|
nuclear@0
|
335 Tracking::TrackingState ss;
|
nuclear@0
|
336 TheSensorStateReader.GetSensorStateAtTime(absTime, ss);
|
nuclear@0
|
337
|
nuclear@0
|
338 // Zero out the status flags
|
nuclear@0
|
339 if (!pClient || !pClient->IsConnected(false, false))
|
nuclear@0
|
340 {
|
nuclear@0
|
341 ss.StatusFlags = 0;
|
nuclear@0
|
342 }
|
nuclear@0
|
343
|
nuclear@0
|
344 return ss;
|
nuclear@0
|
345 }
|
nuclear@0
|
346
|
nuclear@0
|
347 void HMDState::SetEnabledHmdCaps(unsigned hmdCaps)
|
nuclear@0
|
348 {
|
nuclear@0
|
349 if (OurHMDInfo.HmdType < HmdType_DK2)
|
nuclear@0
|
350 {
|
nuclear@0
|
351 // disable low persistence and pentile.
|
nuclear@0
|
352 hmdCaps &= ~ovrHmdCap_LowPersistence;
|
nuclear@0
|
353 hmdCaps &= ~ovrHmdCap_DirectPentile;
|
nuclear@0
|
354
|
nuclear@0
|
355 // disable dynamic prediction using the internal latency tester
|
nuclear@0
|
356 hmdCaps &= ~ovrHmdCap_DynamicPrediction;
|
nuclear@0
|
357 }
|
nuclear@0
|
358
|
nuclear@0
|
359 if (OurHMDInfo.HmdType >= HmdType_DK2)
|
nuclear@0
|
360 {
|
nuclear@0
|
361 if ((EnabledHmdCaps ^ hmdCaps) & ovrHmdCap_DynamicPrediction)
|
nuclear@0
|
362 {
|
nuclear@0
|
363 // DynamicPrediction change
|
nuclear@0
|
364 TimeManager.ResetFrameTiming(TimeManager.GetFrameTiming().FrameIndex,
|
nuclear@0
|
365 (hmdCaps & ovrHmdCap_DynamicPrediction) ? true : false,
|
nuclear@0
|
366 RenderingConfigured);
|
nuclear@0
|
367 }
|
nuclear@0
|
368 }
|
nuclear@0
|
369
|
nuclear@0
|
370 // Pentile unsupported on everything right now.
|
nuclear@0
|
371 hmdCaps &= ~ovrHmdCap_DirectPentile;
|
nuclear@0
|
372
|
nuclear@0
|
373 if ((EnabledHmdCaps ^ hmdCaps) & ovrHmdCap_NoVSync)
|
nuclear@0
|
374 {
|
nuclear@0
|
375 TimeManager.SetVsync((hmdCaps & ovrHmdCap_NoVSync) ? false : true);
|
nuclear@0
|
376 }
|
nuclear@0
|
377
|
nuclear@0
|
378 if ((EnabledHmdCaps ^ hmdCaps) & ovrHmdCap_NoMirrorToWindow)
|
nuclear@0
|
379 {
|
nuclear@0
|
380 #ifdef OVR_OS_WIN32
|
nuclear@0
|
381 Win32::DisplayShim::GetInstance().UseMirroring = (hmdCaps & ovrHmdCap_NoMirrorToWindow) ?
|
nuclear@0
|
382 false : true;
|
nuclear@0
|
383 if (pWindow)
|
nuclear@0
|
384 { // Force window repaint so that stale mirrored image doesn't persist.
|
nuclear@0
|
385 ::InvalidateRect((HWND)pWindow, 0, true);
|
nuclear@0
|
386 }
|
nuclear@0
|
387 #endif
|
nuclear@0
|
388 }
|
nuclear@0
|
389
|
nuclear@0
|
390 // TBD: Should this include be only the rendering flags? Otherwise, bits that failed
|
nuclear@0
|
391 // modification in Hmd_SetEnabledCaps may mis-match...
|
nuclear@0
|
392 EnabledHmdCaps = hmdCaps & ovrHmdCap_Writable_Mask;
|
nuclear@0
|
393 RenderState.EnabledHmdCaps = EnabledHmdCaps;
|
nuclear@0
|
394
|
nuclear@0
|
395
|
nuclear@0
|
396 // If any of the modifiable service caps changed, call on the service.
|
nuclear@0
|
397 unsigned prevServiceCaps = EnabledServiceHmdCaps & ovrHmdCap_Writable_Mask;
|
nuclear@0
|
398 unsigned newServiceCaps = hmdCaps & ovrHmdCap_Writable_Mask & ovrHmdCap_Service_Mask;
|
nuclear@0
|
399
|
nuclear@0
|
400 if (prevServiceCaps ^ newServiceCaps)
|
nuclear@0
|
401 {
|
nuclear@0
|
402 EnabledServiceHmdCaps = pClient ? pClient->Hmd_SetEnabledCaps(NetId, newServiceCaps)
|
nuclear@0
|
403 : newServiceCaps;
|
nuclear@0
|
404 }
|
nuclear@0
|
405 }
|
nuclear@0
|
406
|
nuclear@0
|
407
|
nuclear@0
|
408 unsigned HMDState::SetEnabledHmdCaps()
|
nuclear@0
|
409 {
|
nuclear@0
|
410 unsigned serviceCaps = pClient ? pClient->Hmd_GetEnabledCaps(NetId) :
|
nuclear@0
|
411 EnabledServiceHmdCaps;
|
nuclear@0
|
412
|
nuclear@0
|
413 return serviceCaps & ((~ovrHmdCap_Service_Mask) | EnabledHmdCaps);
|
nuclear@0
|
414 }
|
nuclear@0
|
415
|
nuclear@0
|
416
|
nuclear@0
|
417 //-------------------------------------------------------------------------------------
|
nuclear@0
|
418 // ***** Property Access
|
nuclear@0
|
419
|
nuclear@0
|
420 // FIXME: Remove the EGetBoolValue stuff and do it with a "Server:" prefix, so we do not
|
nuclear@0
|
421 // need to keep a white-list of keys. This is also way cool because it allows us to add
|
nuclear@0
|
422 // new settings keys from outside CAPI that can modify internal server data.
|
nuclear@0
|
423
|
nuclear@0
|
424 bool HMDState::getBoolValue(const char* propertyName, bool defaultVal)
|
nuclear@0
|
425 {
|
nuclear@0
|
426 if (NetSessionCommon::IsServiceProperty(NetSessionCommon::EGetBoolValue, propertyName))
|
nuclear@0
|
427 {
|
nuclear@0
|
428 return NetClient::GetInstance()->GetBoolValue(GetNetId(), propertyName, defaultVal);
|
nuclear@0
|
429 }
|
nuclear@0
|
430 else if (pProfile)
|
nuclear@0
|
431 {
|
nuclear@0
|
432 return pProfile->GetBoolValue(propertyName, defaultVal);
|
nuclear@0
|
433 }
|
nuclear@0
|
434 return defaultVal;
|
nuclear@0
|
435 }
|
nuclear@0
|
436
|
nuclear@0
|
437 bool HMDState::setBoolValue(const char* propertyName, bool value)
|
nuclear@0
|
438 {
|
nuclear@0
|
439 if (NetSessionCommon::IsServiceProperty(NetSessionCommon::ESetBoolValue, propertyName))
|
nuclear@0
|
440 {
|
nuclear@0
|
441 return NetClient::GetInstance()->SetBoolValue(GetNetId(), propertyName, value);
|
nuclear@0
|
442 }
|
nuclear@0
|
443
|
nuclear@0
|
444 return false;
|
nuclear@0
|
445 }
|
nuclear@0
|
446
|
nuclear@0
|
447 int HMDState::getIntValue(const char* propertyName, int defaultVal)
|
nuclear@0
|
448 {
|
nuclear@0
|
449 if (NetSessionCommon::IsServiceProperty(NetSessionCommon::EGetIntValue, propertyName))
|
nuclear@0
|
450 {
|
nuclear@0
|
451 return NetClient::GetInstance()->GetIntValue(GetNetId(), propertyName, defaultVal);
|
nuclear@0
|
452 }
|
nuclear@0
|
453 else if (pProfile)
|
nuclear@0
|
454 {
|
nuclear@0
|
455 return pProfile->GetIntValue(propertyName, defaultVal);
|
nuclear@0
|
456 }
|
nuclear@0
|
457 return defaultVal;
|
nuclear@0
|
458 }
|
nuclear@0
|
459
|
nuclear@0
|
460 bool HMDState::setIntValue(const char* propertyName, int value)
|
nuclear@0
|
461 {
|
nuclear@0
|
462 if (NetSessionCommon::IsServiceProperty(NetSessionCommon::ESetIntValue, propertyName))
|
nuclear@0
|
463 {
|
nuclear@0
|
464 return NetClient::GetInstance()->SetIntValue(GetNetId(), propertyName, value);
|
nuclear@0
|
465 }
|
nuclear@0
|
466
|
nuclear@0
|
467 return false;
|
nuclear@0
|
468 }
|
nuclear@0
|
469
|
nuclear@0
|
470 float HMDState::getFloatValue(const char* propertyName, float defaultVal)
|
nuclear@0
|
471 {
|
nuclear@0
|
472 if (OVR_strcmp(propertyName, "LensSeparation") == 0)
|
nuclear@0
|
473 {
|
nuclear@0
|
474 return OurHMDInfo.LensSeparationInMeters;
|
nuclear@0
|
475 }
|
nuclear@0
|
476 else if (OVR_strcmp(propertyName, "VsyncToNextVsync") == 0)
|
nuclear@0
|
477 {
|
nuclear@0
|
478 return OurHMDInfo.Shutter.VsyncToNextVsync;
|
nuclear@0
|
479 }
|
nuclear@0
|
480 else if (OVR_strcmp(propertyName, "PixelPersistence") == 0)
|
nuclear@0
|
481 {
|
nuclear@0
|
482 return OurHMDInfo.Shutter.PixelPersistence;
|
nuclear@0
|
483 }
|
nuclear@0
|
484 else if (NetSessionCommon::IsServiceProperty(NetSessionCommon::EGetNumberValue, propertyName))
|
nuclear@0
|
485 {
|
nuclear@0
|
486 return (float)NetClient::GetInstance()->GetNumberValue(GetNetId(), propertyName, defaultVal);
|
nuclear@0
|
487 }
|
nuclear@0
|
488 else if (pProfile)
|
nuclear@0
|
489 {
|
nuclear@0
|
490 return pProfile->GetFloatValue(propertyName, defaultVal);
|
nuclear@0
|
491 }
|
nuclear@0
|
492
|
nuclear@0
|
493 return defaultVal;
|
nuclear@0
|
494 }
|
nuclear@0
|
495
|
nuclear@0
|
496 bool HMDState::setFloatValue(const char* propertyName, float value)
|
nuclear@0
|
497 {
|
nuclear@0
|
498 if (NetSessionCommon::IsServiceProperty(NetSessionCommon::ESetNumberValue, propertyName))
|
nuclear@0
|
499 {
|
nuclear@0
|
500 return NetClient::GetInstance()->SetNumberValue(GetNetId(), propertyName, value);
|
nuclear@0
|
501 }
|
nuclear@0
|
502
|
nuclear@0
|
503 return false;
|
nuclear@0
|
504 }
|
nuclear@0
|
505
|
nuclear@0
|
506 static unsigned CopyFloatArrayWithLimit(float dest[], unsigned destSize,
|
nuclear@0
|
507 float source[], unsigned sourceSize)
|
nuclear@0
|
508 {
|
nuclear@0
|
509 unsigned count = Alg::Min(destSize, sourceSize);
|
nuclear@0
|
510 for (unsigned i = 0; i < count; i++)
|
nuclear@0
|
511 dest[i] = source[i];
|
nuclear@0
|
512 return count;
|
nuclear@0
|
513 }
|
nuclear@0
|
514
|
nuclear@0
|
515 unsigned HMDState::getFloatArray(const char* propertyName, float values[], unsigned arraySize)
|
nuclear@0
|
516 {
|
nuclear@0
|
517 if (arraySize)
|
nuclear@0
|
518 {
|
nuclear@0
|
519 if (OVR_strcmp(propertyName, "ScreenSize") == 0)
|
nuclear@0
|
520 {
|
nuclear@0
|
521 float data[2] = { OurHMDInfo.ScreenSizeInMeters.w, OurHMDInfo.ScreenSizeInMeters.h };
|
nuclear@0
|
522
|
nuclear@0
|
523 return CopyFloatArrayWithLimit(values, arraySize, data, 2);
|
nuclear@0
|
524 }
|
nuclear@0
|
525 else if (OVR_strcmp(propertyName, "DistortionClearColor") == 0)
|
nuclear@0
|
526 {
|
nuclear@0
|
527 return CopyFloatArrayWithLimit(values, arraySize, RenderState.ClearColor, 4);
|
nuclear@0
|
528 }
|
nuclear@0
|
529 else if (OVR_strcmp(propertyName, "DK2Latency") == 0)
|
nuclear@0
|
530 {
|
nuclear@0
|
531 if (OurHMDInfo.HmdType != HmdType_DK2)
|
nuclear@0
|
532 {
|
nuclear@0
|
533 return 0;
|
nuclear@0
|
534 }
|
nuclear@0
|
535
|
nuclear@0
|
536 union {
|
nuclear@0
|
537 struct X {
|
nuclear@0
|
538 float latencyRender, latencyTimewarp, latencyPostPresent;
|
nuclear@0
|
539 } x;
|
nuclear@0
|
540 float data[3];
|
nuclear@0
|
541 } m;
|
nuclear@0
|
542
|
nuclear@0
|
543 static_assert(sizeof(m.x)==sizeof(m.data), "sizeof(struct X) failure");
|
nuclear@0
|
544
|
nuclear@0
|
545 TimeManager.GetLatencyTimings(m.x.latencyRender, m.x.latencyTimewarp, m.x.latencyPostPresent);
|
nuclear@0
|
546
|
nuclear@0
|
547 return CopyFloatArrayWithLimit(values, arraySize, m.data, 3);
|
nuclear@0
|
548 }
|
nuclear@0
|
549 else if (NetSessionCommon::IsServiceProperty(NetSessionCommon::EGetNumberValues, propertyName))
|
nuclear@0
|
550 {
|
nuclear@0
|
551 // Convert floats to doubles
|
nuclear@0
|
552 double* da = new double[arraySize];
|
nuclear@0
|
553 for (int i = 0; i < (int)arraySize; ++i)
|
nuclear@0
|
554 {
|
nuclear@0
|
555 da[i] = values[i];
|
nuclear@0
|
556 }
|
nuclear@0
|
557
|
nuclear@0
|
558 int count = NetClient::GetInstance()->GetNumberValues(GetNetId(), propertyName, da, (int)arraySize);
|
nuclear@0
|
559
|
nuclear@0
|
560 for (int i = 0; i < count; ++i)
|
nuclear@0
|
561 {
|
nuclear@0
|
562 values[i] = (float)da[i];
|
nuclear@0
|
563 }
|
nuclear@0
|
564
|
nuclear@0
|
565 delete[] da;
|
nuclear@0
|
566
|
nuclear@0
|
567 return count;
|
nuclear@0
|
568 }
|
nuclear@0
|
569 else if (pProfile)
|
nuclear@0
|
570 {
|
nuclear@0
|
571 // TBD: Not quite right. Should update profile interface, so that
|
nuclear@0
|
572 // we can return 0 in all conditions if property doesn't exist.
|
nuclear@0
|
573
|
nuclear@0
|
574 return pProfile->GetFloatValues(propertyName, values, arraySize);
|
nuclear@0
|
575 }
|
nuclear@0
|
576 }
|
nuclear@0
|
577
|
nuclear@0
|
578 return 0;
|
nuclear@0
|
579 }
|
nuclear@0
|
580
|
nuclear@0
|
581 bool HMDState::setFloatArray(const char* propertyName, float values[], unsigned arraySize)
|
nuclear@0
|
582 {
|
nuclear@0
|
583 if (!arraySize)
|
nuclear@0
|
584 {
|
nuclear@0
|
585 return false;
|
nuclear@0
|
586 }
|
nuclear@0
|
587
|
nuclear@0
|
588 if (OVR_strcmp(propertyName, "DistortionClearColor") == 0)
|
nuclear@0
|
589 {
|
nuclear@0
|
590 CopyFloatArrayWithLimit(RenderState.ClearColor, 4, values, arraySize);
|
nuclear@0
|
591 return true;
|
nuclear@0
|
592 }
|
nuclear@0
|
593
|
nuclear@0
|
594 if (NetSessionCommon::IsServiceProperty(NetSessionCommon::ESetNumberValues, propertyName))
|
nuclear@0
|
595 {
|
nuclear@0
|
596 double* da = new double[arraySize];
|
nuclear@0
|
597 for (int i = 0; i < (int)arraySize; ++i)
|
nuclear@0
|
598 {
|
nuclear@0
|
599 da[i] = values[i];
|
nuclear@0
|
600 }
|
nuclear@0
|
601
|
nuclear@0
|
602 bool result = NetClient::GetInstance()->SetNumberValues(GetNetId(), propertyName, da, arraySize);
|
nuclear@0
|
603
|
nuclear@0
|
604 delete[] da;
|
nuclear@0
|
605
|
nuclear@0
|
606 return result;
|
nuclear@0
|
607 }
|
nuclear@0
|
608
|
nuclear@0
|
609 return false;
|
nuclear@0
|
610 }
|
nuclear@0
|
611
|
nuclear@0
|
612 const char* HMDState::getString(const char* propertyName, const char* defaultVal)
|
nuclear@0
|
613 {
|
nuclear@0
|
614 if (NetSessionCommon::IsServiceProperty(NetSessionCommon::EGetStringValue, propertyName))
|
nuclear@0
|
615 {
|
nuclear@0
|
616 return NetClient::GetInstance()->GetStringValue(GetNetId(), propertyName, defaultVal);
|
nuclear@0
|
617 }
|
nuclear@0
|
618
|
nuclear@0
|
619 if (pProfile)
|
nuclear@0
|
620 {
|
nuclear@0
|
621 LastGetStringValue[0] = 0;
|
nuclear@0
|
622 if (pProfile->GetValue(propertyName, LastGetStringValue, sizeof(LastGetStringValue)))
|
nuclear@0
|
623 {
|
nuclear@0
|
624 return LastGetStringValue;
|
nuclear@0
|
625 }
|
nuclear@0
|
626 }
|
nuclear@0
|
627
|
nuclear@0
|
628 return defaultVal;
|
nuclear@0
|
629 }
|
nuclear@0
|
630
|
nuclear@0
|
631 bool HMDState::setString(const char* propertyName, const char* value)
|
nuclear@0
|
632 {
|
nuclear@0
|
633 if (NetSessionCommon::IsServiceProperty(NetSessionCommon::ESetStringValue, propertyName))
|
nuclear@0
|
634 {
|
nuclear@0
|
635 return NetClient::GetInstance()->SetStringValue(GetNetId(), propertyName, value);
|
nuclear@0
|
636 }
|
nuclear@0
|
637
|
nuclear@0
|
638 return false;
|
nuclear@0
|
639 }
|
nuclear@0
|
640
|
nuclear@0
|
641
|
nuclear@0
|
642 //-------------------------------------------------------------------------------------
|
nuclear@0
|
643 // *** Latency Test
|
nuclear@0
|
644
|
nuclear@0
|
645 bool HMDState::ProcessLatencyTest(unsigned char rgbColorOut[3])
|
nuclear@0
|
646 {
|
nuclear@0
|
647 return NetClient::GetInstance()->LatencyUtil_ProcessInputs(Timer::GetSeconds(), rgbColorOut);
|
nuclear@0
|
648 }
|
nuclear@0
|
649
|
nuclear@0
|
650 //-------------------------------------------------------------------------------------
|
nuclear@0
|
651 // *** Rendering
|
nuclear@0
|
652
|
nuclear@0
|
653 bool HMDState::ConfigureRendering(ovrEyeRenderDesc eyeRenderDescOut[2],
|
nuclear@0
|
654 const ovrFovPort eyeFovIn[2],
|
nuclear@0
|
655 const ovrRenderAPIConfig* apiConfig,
|
nuclear@0
|
656 unsigned distortionCaps)
|
nuclear@0
|
657 {
|
nuclear@0
|
658 ThreadChecker::Scope checkScope(&RenderAPIThreadChecker, "ovrHmd_ConfigureRendering");
|
nuclear@0
|
659
|
nuclear@0
|
660 // null -> shut down.
|
nuclear@0
|
661 if (!apiConfig)
|
nuclear@0
|
662 {
|
nuclear@0
|
663 if (pHSWDisplay)
|
nuclear@0
|
664 {
|
nuclear@0
|
665 pHSWDisplay->Shutdown();
|
nuclear@0
|
666 pHSWDisplay.Clear();
|
nuclear@0
|
667 }
|
nuclear@0
|
668
|
nuclear@0
|
669 if (pRenderer)
|
nuclear@0
|
670 pRenderer.Clear();
|
nuclear@0
|
671 RenderingConfigured = false;
|
nuclear@0
|
672 return true;
|
nuclear@0
|
673 }
|
nuclear@0
|
674
|
nuclear@0
|
675 if (pRenderer &&
|
nuclear@0
|
676 (apiConfig->Header.API != pRenderer->GetRenderAPI()))
|
nuclear@0
|
677 {
|
nuclear@0
|
678 // Shutdown old renderer.
|
nuclear@0
|
679 if (pHSWDisplay)
|
nuclear@0
|
680 {
|
nuclear@0
|
681 pHSWDisplay->Shutdown();
|
nuclear@0
|
682 pHSWDisplay.Clear();
|
nuclear@0
|
683 }
|
nuclear@0
|
684
|
nuclear@0
|
685 if (pRenderer)
|
nuclear@0
|
686 pRenderer.Clear();
|
nuclear@0
|
687 }
|
nuclear@0
|
688
|
nuclear@0
|
689 distortionCaps = distortionCaps & pHmdDesc->DistortionCaps;
|
nuclear@0
|
690
|
nuclear@0
|
691 // Step 1: do basic setup configuration
|
nuclear@0
|
692 RenderState.EnabledHmdCaps = EnabledHmdCaps; // This is a copy... Any cleaner way?
|
nuclear@0
|
693 RenderState.DistortionCaps = distortionCaps;
|
nuclear@0
|
694 RenderState.EyeRenderDesc[0] = RenderState.CalcRenderDesc(ovrEye_Left, eyeFovIn[0]);
|
nuclear@0
|
695 RenderState.EyeRenderDesc[1] = RenderState.CalcRenderDesc(ovrEye_Right, eyeFovIn[1]);
|
nuclear@0
|
696 eyeRenderDescOut[0] = RenderState.EyeRenderDesc[0];
|
nuclear@0
|
697 eyeRenderDescOut[1] = RenderState.EyeRenderDesc[1];
|
nuclear@0
|
698
|
nuclear@0
|
699 TimeManager.ResetFrameTiming(0,
|
nuclear@0
|
700 (EnabledHmdCaps & ovrHmdCap_DynamicPrediction) ? true : false,
|
nuclear@0
|
701 true);
|
nuclear@0
|
702
|
nuclear@0
|
703 LastFrameTimeSeconds = 0.0f;
|
nuclear@0
|
704
|
nuclear@0
|
705 // Set RenderingConfigured early to avoid ASSERTs in renderer initialization.
|
nuclear@0
|
706 RenderingConfigured = true;
|
nuclear@0
|
707
|
nuclear@0
|
708 if (!pRenderer)
|
nuclear@0
|
709 {
|
nuclear@0
|
710 pRenderer = *DistortionRenderer::APICreateRegistry
|
nuclear@0
|
711 [apiConfig->Header.API](pHmdDesc, TimeManager, RenderState);
|
nuclear@0
|
712 }
|
nuclear@0
|
713
|
nuclear@0
|
714 if (!pRenderer ||
|
nuclear@0
|
715 !pRenderer->Initialize(apiConfig))
|
nuclear@0
|
716 {
|
nuclear@0
|
717 RenderingConfigured = false;
|
nuclear@0
|
718 return false;
|
nuclear@0
|
719 }
|
nuclear@0
|
720
|
nuclear@0
|
721 // Setup the Health and Safety Warning display system.
|
nuclear@0
|
722 if(pHSWDisplay && (pHSWDisplay->GetRenderAPIType() != apiConfig->Header.API)) // If we need to reconstruct the HSWDisplay for a different graphics API type, delete the existing display.
|
nuclear@0
|
723 {
|
nuclear@0
|
724 pHSWDisplay->Shutdown();
|
nuclear@0
|
725 pHSWDisplay.Clear();
|
nuclear@0
|
726 }
|
nuclear@0
|
727
|
nuclear@0
|
728 if(!pHSWDisplay) // Use * below because that for of operator= causes it to inherit the refcount the factory gave the object.
|
nuclear@0
|
729 {
|
nuclear@0
|
730 pHSWDisplay = *OVR::CAPI::HSWDisplay::Factory(apiConfig->Header.API, pHmdDesc, RenderState);
|
nuclear@0
|
731 pHSWDisplay->Enable(pProfile->GetBoolValue("HSW", true));
|
nuclear@0
|
732 }
|
nuclear@0
|
733
|
nuclear@0
|
734 if (pHSWDisplay)
|
nuclear@0
|
735 pHSWDisplay->Initialize(apiConfig); // This is potentially re-initializing it with a new config.
|
nuclear@0
|
736
|
nuclear@0
|
737 return true;
|
nuclear@0
|
738 }
|
nuclear@0
|
739
|
nuclear@0
|
740
|
nuclear@0
|
741 void HMDState::SubmitEyeTextures(const ovrPosef renderPose[2],
|
nuclear@0
|
742 const ovrTexture eyeTexture[2])
|
nuclear@0
|
743 {
|
nuclear@0
|
744 RenderState.EyeRenderPoses[0] = renderPose[0];
|
nuclear@0
|
745 RenderState.EyeRenderPoses[1] = renderPose[1];
|
nuclear@0
|
746
|
nuclear@0
|
747 if (pRenderer)
|
nuclear@0
|
748 {
|
nuclear@0
|
749 pRenderer->SubmitEye(0, &eyeTexture[0]);
|
nuclear@0
|
750 pRenderer->SubmitEye(1, &eyeTexture[1]);
|
nuclear@0
|
751 }
|
nuclear@0
|
752 }
|
nuclear@0
|
753
|
nuclear@0
|
754
|
nuclear@0
|
755 // I appreciate this is not an idea place for this function, but it didn't seem to be
|
nuclear@0
|
756 // being linked properly when in OVR_CAPI.cpp.
|
nuclear@0
|
757 // Please relocate if you know of a better place
|
nuclear@0
|
758 ovrBool ovrHmd_CreateDistortionMeshInternal( ovrHmdStruct * hmd,
|
nuclear@0
|
759 ovrEyeType eyeType, ovrFovPort fov,
|
nuclear@0
|
760 unsigned int distortionCaps,
|
nuclear@0
|
761 ovrDistortionMesh *meshData,
|
nuclear@0
|
762 float overrideEyeReliefIfNonZero )
|
nuclear@0
|
763 {
|
nuclear@0
|
764 if (!meshData)
|
nuclear@0
|
765 return 0;
|
nuclear@0
|
766 HMDState* hmds = (HMDState*)hmd;
|
nuclear@0
|
767
|
nuclear@0
|
768 // Not used now, but Chromatic flag or others could possibly be checked for in the future.
|
nuclear@0
|
769 OVR_UNUSED1(distortionCaps);
|
nuclear@0
|
770
|
nuclear@0
|
771 #if defined (OVR_CC_MSVC)
|
nuclear@0
|
772 static_assert(sizeof(DistortionMeshVertexData) == sizeof(ovrDistortionVertex), "DistortionMeshVertexData size mismatch");
|
nuclear@0
|
773 #endif
|
nuclear@0
|
774
|
nuclear@0
|
775 // *** Calculate a part of "StereoParams" needed for mesh generation
|
nuclear@0
|
776
|
nuclear@0
|
777 // Note that mesh distortion generation is invariant of RenderTarget UVs, allowing
|
nuclear@0
|
778 // render target size and location to be changed after the fact dynamically.
|
nuclear@0
|
779 // eyeToSourceUV is computed here for convenience, so that users don't need
|
nuclear@0
|
780 // to call ovrHmd_GetRenderScaleAndOffset unless changing RT dynamically.
|
nuclear@0
|
781
|
nuclear@0
|
782 const HmdRenderInfo& hmdri = hmds->RenderState.RenderInfo;
|
nuclear@0
|
783 StereoEye stereoEye = (eyeType == ovrEye_Left) ? StereoEye_Left : StereoEye_Right;
|
nuclear@0
|
784
|
nuclear@0
|
785 DistortionRenderDesc& distortion = hmds->RenderState.Distortion[eyeType];
|
nuclear@0
|
786 if (overrideEyeReliefIfNonZero)
|
nuclear@0
|
787 {
|
nuclear@0
|
788 distortion.Lens = GenerateLensConfigFromEyeRelief(overrideEyeReliefIfNonZero,hmdri);
|
nuclear@0
|
789 }
|
nuclear@0
|
790
|
nuclear@0
|
791 // Find the mapping from TanAngle space to target NDC space.
|
nuclear@0
|
792 ScaleAndOffset2D eyeToSourceNDC = CreateNDCScaleAndOffsetFromFov(fov);
|
nuclear@0
|
793
|
nuclear@0
|
794 int triangleCount = 0;
|
nuclear@0
|
795 int vertexCount = 0;
|
nuclear@0
|
796
|
nuclear@0
|
797 DistortionMeshCreate((DistortionMeshVertexData**)&meshData->pVertexData,
|
nuclear@0
|
798 (uint16_t**)&meshData->pIndexData,
|
nuclear@0
|
799 &vertexCount, &triangleCount,
|
nuclear@0
|
800 (stereoEye == StereoEye_Right),
|
nuclear@0
|
801 hmdri, distortion, eyeToSourceNDC);
|
nuclear@0
|
802
|
nuclear@0
|
803 if (meshData->pVertexData)
|
nuclear@0
|
804 {
|
nuclear@0
|
805 // Convert to index
|
nuclear@0
|
806 meshData->IndexCount = triangleCount * 3;
|
nuclear@0
|
807 meshData->VertexCount = vertexCount;
|
nuclear@0
|
808 return 1;
|
nuclear@0
|
809 }
|
nuclear@0
|
810
|
nuclear@0
|
811 return 0;
|
nuclear@0
|
812 }
|
nuclear@0
|
813
|
nuclear@0
|
814
|
nuclear@0
|
815
|
nuclear@0
|
816 }} // namespace OVR::CAPI
|