4 * \date 2014-08-04 16:21GMT
5 * \author Jan Boon (Kaetemi)
9 // NeL - MMORPG Framework <https://wiki.ryzom.dev/>
10 // Copyright (C) 2013-2014 Jan BOON (Kaetemi) <jan.boon@kaetemi.be>
12 // This program is free software: you can redistribute it and/or modify
13 // it under the terms of the GNU Affero General Public License as
14 // published by the Free Software Foundation, either version 3 of the
15 // License, or (at your option) any later version.
17 // This program is distributed in the hope that it will be useful,
18 // but WITHOUT ANY WARRANTY; without even the implied warranty of
19 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 // GNU Affero General Public License for more details.
22 // You should have received a copy of the GNU Affero General Public License
23 // along with this program. If not, see <http://www.gnu.org/licenses/>.
25 // Linking this library statically or dynamically with other modules
26 // is making a combined work based on this library. Thus, the terms
27 // and conditions of the GNU General Public License cover the whole
30 // As a special exception, the copyright holders of this library give
31 // you permission to link this library with the Oculus SDK to produce
32 // an executable, regardless of the license terms of the Oculus SDK,
33 // and distribute linked combinations including the two, provided that
34 // you also meet the terms and conditions of the license of the Oculus
35 // SDK. You must obey the GNU General Public License in all respects
36 // for all of the code used other than the Oculus SDK. If you modify
37 // this file, you may extend this exception to your version of the
38 // file, but you are not obligated to do so. If you do not wish to do
39 // so, delete this exception statement from your version.
44 #include "nel/3d/stereo_ovr_04.h"
54 // #include <nel/misc/debug.h>
55 #include "nel/3d/u_camera.h"
56 #include "nel/3d/u_driver.h"
57 #include "nel/3d/material.h"
58 #include "nel/3d/texture_bloom.h"
59 #include "nel/3d/texture_user.h"
60 #include "nel/3d/driver_user.h"
61 #include "nel/3d/u_texture.h"
66 // using namespace NLMISC;
76 #include "stereo_ovr_04_program.h"
78 class CStereoOVRSystem
81 CStereoOVRSystem() : m_InitOk(false)
90 nlwarning("OVR: Not all resources were released before exit");
99 nldebug("OVR: Initialize");
100 m_InitOk
= ovr_Initialize();
111 nldebug("OVR: Release");
122 CStereoOVRSystem s_StereoOVRSystem
;
124 sint s_DeviceCounter
= 0;
129 class CStereoOVRDeviceFactory
: public IStereoDeviceFactory
136 ovrHmdType DebugDeviceType
;
138 IStereoDisplay
*createDevice() const
140 CStereoOVR
*stereo
= new CStereoOVR(this);
141 if (stereo
->isDeviceCreated())
148 static NLMISC::CVector2f
toTex(NLMISC::CVector2f texCoord
, NLMISC::CVector2f uvScaleOffset
[2])
150 // return(EyeToSourceUVScale * flattened + EyeToSourceUVOffset);
151 NLMISC::CVector2f vec
= NLMISC::CVector2f(texCoord
.x
* uvScaleOffset
[0].x
, texCoord
.y
* uvScaleOffset
[0].y
) + uvScaleOffset
[1];
152 // some trial and error voodoo, sorry
153 vec
= (vec
+ NLMISC::CVector2f(1, 1)) * 0.5f
;
154 vec
.y
= 1.0f
- vec
.y
;
155 vec
.x
= 1.0f
- vec
.x
;
159 vec
.x
= 1.0f
- vec
.x
;
164 static float lerp(float f0
, float f1
, float factor
)
166 return (f1
* factor
) + (f0
* (1.0f
- factor
));
169 CStereoOVR::CStereoOVR(const CStereoOVRDeviceFactory
*factory
) : m_DevicePtr(NULL
), m_Stage(0), m_SubStage(0), m_OrientationCached(false), m_Driver(NULL
), m_SceneTexture(NULL
), m_GUITexture(NULL
), m_EyePosition(0.0f
, 0.09f
, 0.15f
), m_Scale(1.0f
), m_AttachedDisplay(false)
171 nlctassert(NL_OVR_EYE_COUNT
== ovrEye_Count
);
173 if (factory
->DetectId
!= s_DetectId
)
175 nlwarning("OVR: Previous device info structures become invalid after listing devices");
179 m_DebugDevice
= factory
->DebugDevice
;
180 if (factory
->DebugDevice
) m_DevicePtr
= ovrHmd_CreateDebug(factory
->DebugDeviceType
);
181 else m_DevicePtr
= ovrHmd_Create(factory
->DeviceIndex
);
185 nlwarning("OVR: Device not created");
191 // nldebug("OVR: HScreenSize: %f, VScreenSize: %f", m_DevicePtr->HMDInfo.HScreenSize, m_DevicePtr->HMDInfo.VScreenSize); // No more support for physically non-square pixels?
192 // nldebug("OVR: VScreenCenter: %f", m_DevicePtr->HMDInfo.VScreenCenter);
193 // nldebug("OVR: EyeToScreenDistance: %f", m_DevicePtr->HMDInfo.EyeToScreenDistance);
194 // nldebug("OVR: LensSeparationDistance: %f", m_DevicePtr->HMDInfo.LensSeparationDistance);
195 // nldebug("OVR: InterpupillaryDistance: %f", m_DevicePtr->HMDInfo.InterpupillaryDistance);
196 nldebug("OVR: Resolution.w: %i, Resolution.h: %i", m_DevicePtr
->Resolution
.w
, m_DevicePtr
->Resolution
.h
);
197 // nldebug("OVR: DistortionK[0]: %f, DistortionK[1]: %f", m_DevicePtr->HMDInfo.DistortionK[0], m_DevicePtr->HMDInfo.DistortionK[1]);
198 // nldebug("OVR: DistortionK[2]: %f, DistortionK[3]: %f", m_DevicePtr->HMDInfo.DistortionK[2], m_DevicePtr->HMDInfo.DistortionK[3]);
200 if (!ovrHmd_ConfigureTracking(m_DevicePtr
,
201 ovrTrackingCap_Orientation
| ovrTrackingCap_MagYawCorrection
, // | ovrTrackingCap_Position
202 ovrTrackingCap_Orientation
))
204 nlwarning("OVR: Cannot configure tracking");
205 ovrHmd_Destroy(m_DevicePtr
);
211 float nativeWidth
= m_DevicePtr
->Resolution
.w
;
212 float nativeHeight
= m_DevicePtr
->Resolution
.h
;
214 // get render descriptions for default fov
215 ovrEyeRenderDesc eyeRenderDesc
[ovrEye_Count
];
216 eyeRenderDesc
[ovrEye_Left
] = ovrHmd_GetRenderDesc(m_DevicePtr
, ovrEye_Left
, m_DevicePtr
->DefaultEyeFov
[ovrEye_Left
]);
217 eyeRenderDesc
[ovrEye_Right
] = ovrHmd_GetRenderDesc(m_DevicePtr
, ovrEye_Right
, m_DevicePtr
->DefaultEyeFov
[ovrEye_Right
]);
218 nldebug("OVR: LEFT DistortedViewport: x: %i, y: %i, w: %i, h: %i", eyeRenderDesc
[0].DistortedViewport
.Pos
.x
, eyeRenderDesc
[0].DistortedViewport
.Pos
.y
, eyeRenderDesc
[0].DistortedViewport
.Size
.w
, eyeRenderDesc
[0].DistortedViewport
.Size
.h
);
219 nldebug("OVR: LEFT PixelsPerTanAngleAtCenter: x: %f, y: %f ", eyeRenderDesc
[0].PixelsPerTanAngleAtCenter
.x
, eyeRenderDesc
[0].PixelsPerTanAngleAtCenter
.y
);
220 nldebug("OVR: LEFT ViewAdjust: x: %f, y: %f, z: %f ", eyeRenderDesc
[0].ViewAdjust
.x
, eyeRenderDesc
[0].ViewAdjust
.y
, eyeRenderDesc
[0].ViewAdjust
.z
);
221 nldebug("OVR: RIGHT DistortedViewport: x: %i, y: %i, w: %i, h: %i", eyeRenderDesc
[1].DistortedViewport
.Pos
.x
, eyeRenderDesc
[1].DistortedViewport
.Pos
.y
, eyeRenderDesc
[1].DistortedViewport
.Size
.w
, eyeRenderDesc
[1].DistortedViewport
.Size
.h
);
222 nldebug("OVR: RIGHT PixelsPerTanAngleAtCenter: x: %f, y: %f ", eyeRenderDesc
[1].PixelsPerTanAngleAtCenter
.x
, eyeRenderDesc
[1].PixelsPerTanAngleAtCenter
.y
);
223 nldebug("OVR: RIGHT ViewAdjust: x: %f, y: %f, z: %f ", eyeRenderDesc
[1].ViewAdjust
.x
, eyeRenderDesc
[1].ViewAdjust
.y
, eyeRenderDesc
[1].ViewAdjust
.z
);
225 // 2014/08/04 19:54:25 DBG a60 snowballs_client.exe stereo_ovr_04.cpp 171 NL3D::CStereoOVR::CStereoOVR : OVR: Resolution.w: 1280, Resolution.h: 800
226 // 2014/08/04 19:54:25 DBG a60 snowballs_client.exe stereo_ovr_04.cpp 189 NL3D::CStereoOVR::CStereoOVR : OVR: LEFT DistortedViewport: x: 0, y: 0, w: 640, h: 800
227 // 2014/08/04 19:54:25 DBG a60 snowballs_client.exe stereo_ovr_04.cpp 190 NL3D::CStereoOVR::CStereoOVR : OVR: LEFT PixelsPerTanAngleAtCenter: x: 363.247864, y: 363.247864
228 // 2014/08/04 19:54:25 DBG a60 snowballs_client.exe stereo_ovr_04.cpp 191 NL3D::CStereoOVR::CStereoOVR : OVR: LEFT ViewAdjust: x: 0.031800, y: 0.000000, z: 0.000000
229 // 2014/08/04 19:55:46 DBG 2e18 snowballs_client.exe stereo_ovr_04.cpp 192 NL3D::CStereoOVR::CStereoOVR : OVR: RIGHT DistortedViewport: x: 640, y: 0, w: 640, h: 800
230 // 2014/08/04 19:55:46 DBG 2e18 snowballs_client.exe stereo_ovr_04.cpp 193 NL3D::CStereoOVR::CStereoOVR : OVR: RIGHT PixelsPerTanAngleAtCenter: x: 363.247864, y: 363.247864
231 // 2014/08/04 19:55:46 DBG 2e18 snowballs_client.exe stereo_ovr_04.cpp 194 NL3D::CStereoOVR::CStereoOVR : OVR: RIGHT ViewAdjust: x: -0.031868, y: 0.000000, z: 0.000000
233 // find out the recommended render target size
234 ovrSizei fovTextureSize
[ovrEye_Count
];
235 fovTextureSize
[ovrEye_Left
] = ovrHmd_GetFovTextureSize(m_DevicePtr
, ovrEye_Left
, eyeRenderDesc
[ovrEye_Left
].Fov
, 1.0f
);
236 fovTextureSize
[ovrEye_Right
] = ovrHmd_GetFovTextureSize(m_DevicePtr
, ovrEye_Right
, eyeRenderDesc
[ovrEye_Right
].Fov
, 1.0f
);
237 m_RenderTargetWidth
= fovTextureSize
[ovrEye_Left
].w
+ fovTextureSize
[ovrEye_Right
].w
;
238 m_RenderTargetHeight
= max(fovTextureSize
[ovrEye_Left
].h
, fovTextureSize
[ovrEye_Right
].h
);
239 nldebug("OVR: RenderTarget: w: %u, h: %u", m_RenderTargetWidth
, m_RenderTargetHeight
);
241 // 2014/08/04 20:22:03 DBG 30e4 snowballs_client.exe stereo_ovr_04.cpp 213 NL3D::CStereoOVR::CStereoOVR : OVR: RenderTarget: w: 2414, h: 1870 // That looks a bit excessive...
243 for (uint eye
= 0; eye
< ovrEye_Count
; ++eye
)
245 ovrFovPort
&fov
= eyeRenderDesc
[eye
].Fov
;
248 m_EyeViewAdjustX
[eye
] = -eyeRenderDesc
[eye
].ViewAdjust
.x
;
251 m_EyeViewport
[eye
].init(
252 (float)eyeRenderDesc
[eye
].DistortedViewport
.Pos
.x
/ nativeWidth
,
253 (float)eyeRenderDesc
[eye
].DistortedViewport
.Pos
.y
/ nativeHeight
,
254 (float)eyeRenderDesc
[eye
].DistortedViewport
.Size
.w
/ nativeWidth
,
255 (float)eyeRenderDesc
[eye
].DistortedViewport
.Size
.h
/ nativeHeight
);
256 nldebug("OVR: EyeViewport: x: %f, y: %f, w: %f, h: %f", m_EyeViewport
[eye
].getX(), m_EyeViewport
[eye
].getY(), m_EyeViewport
[eye
].getWidth(), m_EyeViewport
[eye
].getHeight());
257 ovrRecti eyeViewport
;
258 eyeViewport
.Pos
.x
= (eyeRenderDesc
[eye
].DistortedViewport
.Pos
.x
* m_RenderTargetWidth
) / m_DevicePtr
->Resolution
.w
;
259 eyeViewport
.Pos
.y
= (eyeRenderDesc
[eye
].DistortedViewport
.Pos
.y
* m_RenderTargetHeight
) / m_DevicePtr
->Resolution
.h
;
260 eyeViewport
.Size
.w
= (eyeRenderDesc
[eye
].DistortedViewport
.Size
.w
* m_RenderTargetWidth
) / m_DevicePtr
->Resolution
.w
;
261 eyeViewport
.Size
.h
= (eyeRenderDesc
[eye
].DistortedViewport
.Size
.h
* m_RenderTargetHeight
) / m_DevicePtr
->Resolution
.h
;
263 // calculate hfov and ar
264 /*float combinedTanHalfFovHorizontal = max(fov.LeftTan, fov.RightTan);
265 float combinedTanHalfFovVertical = max(fov.UpTan, fov.DownTan);
266 float horizontalFullFovInRadians = 2.0f * atanf (combinedTanHalfFovHorizontal);
267 float aspectRatio = combinedTanHalfFovHorizontal / combinedTanHalfFovVertical;
268 float m_EyeHFov[NL_OVR_EYE_COUNT];
269 float m_EyeAR[NL_OVR_EYE_COUNT];
270 m_EyeHFov[eye] = horizontalFullFovInRadians;
271 m_EyeAR[eye] = aspectRatio;
272 nldebug("OVR: HFOV: %f, AR: %f", horizontalFullFovInRadians, aspectRatio);
273 m_EyeFrustumBase[eye].initPerspective(m_EyeHFov[eye], m_EyeAR[eye], 1.0f, 100.f);
274 nldebug("OVR: FOV: Left: %f, Right: %f, Down: %f, Up: %f", // DOUBLE CHECK
275 m_EyeFrustumBase[eye].Left, m_EyeFrustumBase[eye].Right, m_EyeFrustumBase[eye].Bottom, m_EyeFrustumBase[eye].Top);*/
276 m_EyeFrustumBase
[eye
].init(
277 -fov
.LeftTan
, // OVR provides positive values
278 fov
.RightTan
, // DEBUG: If renders shifted left and right, swap left and right
280 fov
.UpTan
, // DEBUG: If renders shifted up or down, swap down and up
284 nldebug("OVR: FOV: Left: %f, Right: %f, Down: %f, Up: %f",
285 m_EyeFrustumBase
[eye
].Left
, m_EyeFrustumBase
[eye
].Right
, m_EyeFrustumBase
[eye
].Bottom
, m_EyeFrustumBase
[eye
].Top
);
287 // get distortion mesh
288 ovrDistortionMesh meshData
;
289 ovrHmd_CreateDistortionMesh(m_DevicePtr
, (ovrEyeType
)eye
, fov
,
290 ovrDistortionCap_Chromatic
/*| ovrDistortionCap_TimeWarp*/ | ovrDistortionCap_Vignette
, // I believe the timewarp gimmick screws with parallax
292 ovrVector2f uvScaleOffset
[2];
294 // get parameters for programs
295 ovrHmd_GetRenderScaleAndOffset(fov
,
296 fovTextureSize
[eye
], eyeViewport
,
297 (ovrVector2f
*)uvScaleOffset
);
298 m_EyeUVScaleOffset
[eye
][0] = NLMISC::CVector2f(uvScaleOffset
[0].x
, uvScaleOffset
[0].y
);
299 m_EyeUVScaleOffset
[eye
][1] = NLMISC::CVector2f(uvScaleOffset
[1].x
, uvScaleOffset
[1].y
);
302 float chromaFactor
= 1.00f
;
303 if (m_DevicePtr
->Type
== ovrHmd_DK2
)
304 chromaFactor
= 0.75f
;
306 // create distortion mesh vertex buffer
307 m_VB
[eye
].setVertexFormat(CVertexBuffer::PositionFlag
| CVertexBuffer::TexCoord0Flag
| CVertexBuffer::TexCoord1Flag
| CVertexBuffer::TexCoord2Flag
| CVertexBuffer::PrimaryColorFlag
);
308 m_VB
[eye
].setPreferredMemory(CVertexBuffer::StaticPreferred
, true);
309 m_VB
[eye
].setNumVertices(meshData
.VertexCount
);
311 CVertexBufferReadWrite vba
;
313 for (uint i
= 0; i
< meshData
.VertexCount
; ++i
)
315 ovrDistortionVertex
&ov
= meshData
.pVertexData
[i
];
316 vba
.setVertexCoord(i
, (ov
.ScreenPosNDC
.x
+ 1.0f
) * 0.5f
, (ov
.ScreenPosNDC
.y
+ 1.0f
) * 0.5f
, 0.5f
);
317 NLMISC::CVector2f
texR(
318 lerp(ov
.TanEyeAnglesG
.x
, ov
.TanEyeAnglesR
.x
, chromaFactor
),
319 lerp(ov
.TanEyeAnglesG
.y
, ov
.TanEyeAnglesR
.y
, chromaFactor
));
320 NLMISC::CVector2f
texG(ov
.TanEyeAnglesG
.x
, ov
.TanEyeAnglesG
.y
);
321 NLMISC::CVector2f
texB(
322 lerp(ov
.TanEyeAnglesG
.x
, ov
.TanEyeAnglesB
.x
, chromaFactor
),
323 lerp(ov
.TanEyeAnglesG
.y
, ov
.TanEyeAnglesB
.y
, chromaFactor
));
324 texR
= toTex(texR
, m_EyeUVScaleOffset
[eye
]);
325 texG
= toTex(texG
, m_EyeUVScaleOffset
[eye
]);
326 texB
= toTex(texB
, m_EyeUVScaleOffset
[eye
]);
327 vba
.setTexCoord(i
, 0, texR
.x
, texR
.y
);
328 vba
.setTexCoord(i
, 1, texG
.x
, texG
.y
);
329 vba
.setTexCoord(i
, 2, texB
.x
, texB
.y
);
331 color
.R
= color
.G
= color
.B
= (uint8
)(ov
.VignetteFactor
* 255.99f
);
332 color
.A
= 255; // (uint8)(ov.TimeWarpFactor * 255.99f);
333 vba
.setColor(i
, color
);
337 // create distortion mesh index buffer
338 m_IB
[eye
].setFormat(NL_DEFAULT_INDEX_BUFFER_FORMAT
);
339 m_IB
[eye
].setPreferredMemory(CIndexBuffer::StaticPreferred
, true);
340 m_IB
[eye
].setNumIndexes(meshData
.IndexCount
);
342 CIndexBufferReadWrite iba
;
344 for (uint i
= 0; i
+ 2 < meshData
.IndexCount
; i
+= 3)
346 nlassert(meshData
.pIndexData
[i
] < meshData
.VertexCount
);
347 nlassert(meshData
.pIndexData
[i
+ 1] < meshData
.VertexCount
);
348 nlassert(meshData
.pIndexData
[i
+ 2] < meshData
.VertexCount
);
349 iba
.setTri(i
, meshData
.pIndexData
[i
], meshData
.pIndexData
[i
+ 1], meshData
.pIndexData
[i
+ 2]);
354 m_NbTris
[eye
] = meshData
.IndexCount
/ 3;
356 // destroy ovr distortion mesh
357 ovrHmd_DestroyDistortionMesh(&meshData
);
360 // 2014/08/04 20:22:03 DBG 30e4 snowballs_client.exe stereo_ovr_04.cpp 222 NL3D::CStereoOVR::CStereoOVR : OVR: EyeViewport: x: 0.000000, y: 0.000000, w: 0.500000, h: 1.000000
361 // 2014/08/04 22:28:39 DBG 3040 snowballs_client.exe stereo_ovr_04.cpp 235 NL3D::CStereoOVR::CStereoOVR : OVR: HFOV: 2.339905, AR: 0.916641
362 // 2014/08/04 20:22:03 DBG 30e4 snowballs_client.exe stereo_ovr_04.cpp 222 NL3D::CStereoOVR::CStereoOVR : OVR: EyeViewport: x: 0.500000, y: 0.000000, w: 0.500000, h: 1.000000
363 // 2014/08/04 22:28:39 DBG 3040 snowballs_client.exe stereo_ovr_04.cpp 235 NL3D::CStereoOVR::CStereoOVR : OVR: HFOV: 2.339905, AR: 0.916641
365 ovrHmd_RecenterPose(m_DevicePtr
);
368 /*nldebug("OVR: Early exit");
369 ovrHmd_Destroy(m_DevicePtr);
374 CStereoOVR::~CStereoOVR()
376 if (m_AttachedDisplay
)
381 if (!m_UnlitMat
.empty())
383 m_Driver
->deleteMaterial(m_UnlitMat
);
390 ovrHmd_Destroy(m_DevicePtr
);
396 void CStereoOVR::setDriver(NL3D::UDriver
*driver
)
400 CDriverUser
*dru
= static_cast<CDriverUser
*>(driver
);
401 IDriver
*drv
= dru
->getDriver();
403 m_UnlitMat
= m_Driver
->createMaterial();
404 m_UnlitMat
.initUnlit();
405 m_UnlitMat
.setColor(CRGBA::White
);
406 m_UnlitMat
.setBlend (false);
407 m_UnlitMat
.setAlphaTest (false);
408 NL3D::CMaterial
*unlitMat
= m_UnlitMat
.getObjectPtr();
409 unlitMat
->setShader(NL3D::CMaterial::Normal
);
410 unlitMat
->setBlendFunc(CMaterial::one
, CMaterial::zero
);
411 unlitMat
->setZWrite(false);
412 unlitMat
->setZFunc(CMaterial::always
);
413 unlitMat
->setDoubleSided(true);
415 unlitMat
->texConstantColor(0, NLMISC::CRGBA(255, 0, 0, 0));
416 unlitMat
->texConstantColor(1, NLMISC::CRGBA(0, 255, 0, 0));
417 unlitMat
->texConstantColor(2, NLMISC::CRGBA(0, 0, 255, 0));
419 m_UnlitMat
.texEnvArg0RGB(0, UMaterial::Texture
, UMaterial::SrcColor
);
420 m_UnlitMat
.texEnvArg1RGB(0, UMaterial::Constant
, UMaterial::SrcColor
);
421 m_UnlitMat
.texEnvOpRGB(0, UMaterial::Modulate
);
423 m_UnlitMat
.texEnvArg0RGB(1, UMaterial::Texture
, UMaterial::SrcColor
);
424 m_UnlitMat
.texEnvArg1RGB(1, UMaterial::Constant
, UMaterial::SrcColor
);
425 m_UnlitMat
.texEnvArg2RGB(1, UMaterial::Previous
, UMaterial::SrcColor
);
426 m_UnlitMat
.texEnvOpRGB(1, UMaterial::Mad
);
428 m_UnlitMat
.texEnvArg0RGB(2, UMaterial::Texture
, UMaterial::SrcColor
);
429 m_UnlitMat
.texEnvArg1RGB(2, UMaterial::Constant
, UMaterial::SrcColor
);
430 m_UnlitMat
.texEnvArg2RGB(2, UMaterial::Previous
, UMaterial::SrcColor
);
431 m_UnlitMat
.texEnvOpRGB(2, UMaterial::Mad
);
433 m_UnlitMat
.texEnvArg0RGB(3, UMaterial::Previous
, UMaterial::SrcColor
);
434 m_UnlitMat
.texEnvArg1RGB(3, UMaterial::Diffuse
, UMaterial::SrcColor
);
435 m_UnlitMat
.texEnvOpRGB(3, UMaterial::Modulate
);
438 bool CStereoOVR::getScreenResolution(uint
&width
, uint
&height
)
442 width
= m_DevicePtr
->Resolution
.w
;
443 height
= m_DevicePtr
->Resolution
.h
;
449 bool CStereoOVR::attachToDisplay()
451 nldebug("OVR: Attach to display '%s'", m_DevicePtr
->DisplayDeviceName
);
456 if (!m_AttachedDisplay
)
458 m_Driver
->getCurrentScreenMode(m_OriginalMode
);
459 m_Driver
->getWindowPos(m_OriginalWinPosX
, m_OriginalWinPosY
);
462 #if defined(NL_OS_WINDOWS)
463 if ((m_DevicePtr
->HmdCaps
& ovrHmdCap_ExtendDesktop
) != ovrHmdCap_ExtendDesktop
)
465 nldebug("OVR: Direct Rift");
466 CDriverUser
*dru
= static_cast<CDriverUser
*>(m_Driver
);
467 IDriver
*drv
= dru
->getDriver();
468 m_AttachedDisplay
= ovrHmd_AttachToWindow(m_DevicePtr
, (void *)drv
->getDisplay(), NULL
, NULL
);
469 if (!m_AttachedDisplay
)
470 nlwarning("OVR: Direct Rift failed!");
475 nldebug("OVR: Extended Rift");
477 mode
.DisplayDevice
= m_DevicePtr
->DisplayDeviceName
;
478 mode
.Windowed
= false;
479 mode
.Width
= m_DevicePtr
->Resolution
.w
;
480 mode
.Height
= m_DevicePtr
->Resolution
.h
;
481 m_Driver
->setMode(mode
);
482 m_AttachedDisplay
= true;
485 return m_AttachedDisplay
;
488 void CStereoOVR::detachFromDisplay()
490 /*if (!m_OriginalMode.Windowed)
492 m_OriginalMode.Windowed = true;
493 m_Driver->setMode(m_OriginalMode);
494 m_OriginalMode.Windowed = false;
496 m_Driver
->setMode(m_OriginalMode
);
497 m_Driver
->setWindowPos(m_OriginalWinPosX
, m_OriginalWinPosY
);
498 m_AttachedDisplay
= false;
501 void CStereoOVR::initCamera(uint cid
, const NL3D::UCamera
*camera
)
503 m_OriginalFrustum
[cid
] = camera
->getFrustum();
505 /*m_LeftFrustum[cid] = m_OriginalFrustum[cid];
506 m_RightFrustum[cid] = m_OriginalFrustum[cid];
507 m_ClippingFrustum[cid] = m_OriginalFrustum[cid];
510 m_LeftFrustum
[cid
].init(
511 m_EyeFrustumBase
[ovrEye_Left
].Left
* camera
->getFrustum().Near
,
512 m_EyeFrustumBase
[ovrEye_Left
].Right
* camera
->getFrustum().Near
,
513 m_EyeFrustumBase
[ovrEye_Left
].Bottom
* camera
->getFrustum().Near
,
514 m_EyeFrustumBase
[ovrEye_Left
].Top
* camera
->getFrustum().Near
,
515 camera
->getFrustum().Near
,
516 camera
->getFrustum().Far
,
519 m_RightFrustum
[cid
].init(
520 m_EyeFrustumBase
[ovrEye_Right
].Left
* camera
->getFrustum().Near
,
521 m_EyeFrustumBase
[ovrEye_Right
].Right
* camera
->getFrustum().Near
,
522 m_EyeFrustumBase
[ovrEye_Right
].Bottom
* camera
->getFrustum().Near
,
523 m_EyeFrustumBase
[ovrEye_Right
].Top
* camera
->getFrustum().Near
,
524 camera
->getFrustum().Near
,
525 camera
->getFrustum().Far
,
528 m_ClippingFrustum
[cid
].init(
529 min(m_EyeFrustumBase
[ovrEye_Left
].Left
, m_EyeFrustumBase
[ovrEye_Right
].Left
) * camera
->getFrustum().Near
,
530 max(m_EyeFrustumBase
[ovrEye_Left
].Right
, m_EyeFrustumBase
[ovrEye_Right
].Right
) * camera
->getFrustum().Near
,
531 min(m_EyeFrustumBase
[ovrEye_Left
].Bottom
, m_EyeFrustumBase
[ovrEye_Right
].Bottom
) * camera
->getFrustum().Near
,
532 max(m_EyeFrustumBase
[ovrEye_Left
].Top
, m_EyeFrustumBase
[ovrEye_Right
].Top
) * camera
->getFrustum().Near
,
533 camera
->getFrustum().Near
,
534 camera
->getFrustum().Far
,
538 /// Get the frustum to use for clipping
539 void CStereoOVR::getClippingFrustum(uint cid
, NL3D::UCamera
*camera
) const
541 camera
->setFrustum(m_ClippingFrustum
[cid
]);
544 /// Get the original frustum of the camera
545 void CStereoOVR::getOriginalFrustum(uint cid
, NL3D::UCamera
*camera
) const
547 camera
->setFrustum(m_OriginalFrustum
[cid
]);
550 void CStereoOVR::updateCamera(uint cid
, const NL3D::UCamera
*camera
)
552 if (camera
->getFrustum().Near
!= m_LeftFrustum
[cid
].Near
553 || camera
->getFrustum().Far
!= m_LeftFrustum
[cid
].Far
)
554 CStereoOVR::initCamera(cid
, camera
);
555 m_CameraMatrix
[cid
] = camera
->getMatrix();
558 bool CStereoOVR::nextPass()
560 if (m_Driver
->getPolygonMode() == UDriver::Filled
)
562 switch (m_Stage
) // Previous stage
568 // draw interface 2d (onto render target)
589 // draw interface 3d left
595 // draw interface 3d right
601 // (endInterfacesDisplayBloom)
602 // draw interface 2d left
608 // draw interface 2d right
614 m_OrientationCached
= false;
632 nlerror("Invalid stage");
635 m_OrientationCached
= false;
639 const NL3D::CViewport
&CStereoOVR::getCurrentViewport() const
641 if (m_Stage
== 2) return m_RegularViewport
;
642 else if (m_Stage
% 2) return m_EyeViewport
[ovrEye_Left
];
643 else return m_EyeViewport
[ovrEye_Right
];
646 const NL3D::CFrustum
&CStereoOVR::getCurrentFrustum(uint cid
) const
648 if (m_Stage
== 2) return m_OriginalFrustum
[cid
];
649 else if (m_Stage
% 2) return m_LeftFrustum
[cid
];
650 else return m_RightFrustum
[cid
];
653 void CStereoOVR::getCurrentFrustum(uint cid
, NL3D::UCamera
*camera
) const
655 if (m_Stage
== 2) camera
->setFrustum(m_OriginalFrustum
[cid
]);
656 else if (m_Stage
% 2) camera
->setFrustum(m_LeftFrustum
[cid
]);
657 else camera
->setFrustum(m_RightFrustum
[cid
]);
660 void CStereoOVR::getCurrentMatrix(uint cid
, NL3D::UCamera
*camera
) const
663 if (m_Stage
== 2) { }
664 else if (m_Stage
% 2) translate
.translate(CVector(m_EyeViewAdjustX
[ovrEye_Left
] * m_Scale
, 0.f
, 0.f
)); // ok
665 else translate
.translate(CVector(m_EyeViewAdjustX
[ovrEye_Right
] * m_Scale
, 0.f
, 0.f
)); // ok
666 CMatrix mat
= m_CameraMatrix
[cid
] * translate
;
667 if (camera
->getTransformMode() == NL3D::UTransformable::RotQuat
)
669 camera
->setPos(mat
.getPos());
670 camera
->setRotQuat(mat
.getRot());
674 // camera->setTransformMode(NL3D::UTransformable::DirectMatrix);
675 camera
->setMatrix(mat
);
679 bool CStereoOVR::wantClear()
687 return m_Driver
->getPolygonMode() != UDriver::Filled
;
690 bool CStereoOVR::wantScene()
699 return m_Driver
->getPolygonMode() != UDriver::Filled
;
702 bool CStereoOVR::wantSceneEffects()
709 return m_Driver
->getPolygonMode() != UDriver::Filled
;
712 bool CStereoOVR::wantInterface3D()
721 return m_Driver
->getPolygonMode() != UDriver::Filled
;
724 bool CStereoOVR::wantInterface2D()
732 return m_Driver
->getPolygonMode() != UDriver::Filled
;
735 bool CStereoOVR::isSceneFirst()
744 return m_Driver
->getPolygonMode() != UDriver::Filled
;
747 bool CStereoOVR::isSceneLast()
756 return m_Driver
->getPolygonMode() != UDriver::Filled
;
759 /// Returns non-NULL if a new render target was set
760 bool CStereoOVR::beginRenderTarget()
762 // render target always set before driver clear
763 // nlassert(m_SubStage <= 1);
765 // Set GUI render target
766 if (m_Driver
&& m_Stage
== 2 && (m_Driver
->getPolygonMode() == UDriver::Filled
))
768 nlassert(!m_GUITexture
);
769 uint32 width
, height
;
770 m_Driver
->getWindowSize(width
, height
);
771 m_GUITexture
= m_Driver
->getRenderTargetManager().getRenderTarget(width
, height
, true, UTexture::RGBA8888
);
772 static_cast<CDriverUser
*>(m_Driver
)->setRenderTarget(*m_GUITexture
);
773 m_Driver
->clearBuffers(NLMISC::CRGBA(0, 0, 0, 0));
777 // Begin 3D scene render target
778 if (m_Driver
&& m_Stage
== 3 && (m_Driver
->getPolygonMode() == UDriver::Filled
))
780 nlassert(!m_SceneTexture
);
781 m_SceneTexture
= m_Driver
->getRenderTargetManager().getRenderTarget(m_RenderTargetWidth
, m_RenderTargetHeight
);
782 static_cast<CDriverUser
*>(m_Driver
)->setRenderTarget(*m_SceneTexture
);
784 /*nldebug("OVR: Begin render target");*/
785 //m_Driver->beginDefaultRenderTarget(m_RenderTargetWidth, m_RenderTargetHeight); // DEBUG
792 void CStereoOVR::setInterfaceMatrix(const NL3D::CMatrix
&matrix
)
794 m_InterfaceCameraMatrix
= matrix
;
797 void CStereoOVR::renderGUI()
799 m_Driver
->setModelMatrix(m_InterfaceCameraMatrix
);
802 NLMISC::CLine line(NLMISC::CVector(0, 5, 2), NLMISC::CVector(0, 5, 3));
804 NL3D::UMaterial mat = m_Driver->createMaterial();
805 mat.setZWrite(false);
806 // mat.setZFunc(UMaterial::always); // Not nice!
807 mat.setDoubleSided(true);
808 mat.setColor(NLMISC::CRGBA::Red);
811 m_Driver->drawLine(line, mat);
813 m_Driver->deleteMaterial(mat);
817 NL3D::UMaterial mat = m_Driver->createMaterial();
818 mat.setZWrite(false);
819 mat.setZFunc(UMaterial::always); // Not nice!
820 mat.setDoubleSided(true);
824 mat.setColor(NLMISC::CRGBA::Red);
825 line = NLMISC::CLine(NLMISC::CVector(0, 3, -3), NLMISC::CVector(0, 3, 3)); // YPos
826 m_Driver->drawLine(line, mat);
828 mat.setColor(NLMISC::CRGBA::Green);
829 line = NLMISC::CLine(NLMISC::CVector(3, 0, -3), NLMISC::CVector(3, 0, 3)); // XPos
830 m_Driver->drawLine(line, mat);
832 mat.setColor(NLMISC::CRGBA::Magenta);
833 line = NLMISC::CLine(NLMISC::CVector(0, -3, -3), NLMISC::CVector(0, -3, 3)); // YNeg
834 m_Driver->drawLine(line, mat);
836 mat.setColor(NLMISC::CRGBA::Cyan);
837 line = NLMISC::CLine(NLMISC::CVector(-3, 0, -3), NLMISC::CVector(-3, 0, 3)); // XNeg
838 m_Driver->drawLine(line, mat);
840 mat.setColor(NLMISC::CRGBA::Blue);
841 line = NLMISC::CLine(NLMISC::CVector(0, -3, 3), NLMISC::CVector(0, 3, 3)); // ZPos
842 m_Driver->drawLine(line, mat);
844 mat.setColor(NLMISC::CRGBA::Blue);
845 line = NLMISC::CLine(NLMISC::CVector(0, -3, -3), NLMISC::CVector(0, 3, -3)); // ZNeg
846 m_Driver->drawLine(line, mat);
848 m_Driver->deleteMaterial(mat);
852 nlassert(m_GUITexture
);
854 NLMISC::CQuadUV quad
;
856 NL3D::UMaterial umat
= m_Driver
->createMaterial();
858 umat
.setColor(NLMISC::CRGBA::White
);
859 umat
.setDoubleSided(true);
861 umat
.setAlphaTest(false);
862 NL3D::CMaterial
*mat
= umat
.getObjectPtr();
863 mat
->setShader(NL3D::CMaterial::Normal
);
864 mat
->setBlendFunc(CMaterial::one
, CMaterial::invsrcalpha
);
865 mat
->setZWrite(false);
866 // mat->setZFunc(CMaterial::always); // Not nice
867 mat
->setDoubleSided(true);
868 mat
->setTexture(0, m_GUITexture
->getITexture());
872 float distance
= 1.5f
;
873 float offcenter
= 0.75f
;
875 float height
= scale
* distance
* 2.0f
;
878 m_Driver
->getWindowSize(winw
, winh
);
879 float width
= height
* (float)winw
/ (float)winh
;
881 float bottom
= -(height
* 0.5f
);
882 float top
= (height
* 0.5f
);
884 NLMISC::CQuadUV quadUV
;
885 quadUV
.V0
= CVector(-(width
* 0.5f
), distance
, -(height
* 0.5f
));
886 quadUV
.V1
= CVector((width
* 0.5f
), distance
, -(height
* 0.5f
));
887 quadUV
.V2
= CVector((width
* 0.5f
), distance
, (height
* 0.5f
));
888 quadUV
.V3
= CVector(-(width
* 0.5f
), distance
, (height
* 0.5f
));
889 quadUV
.Uv0
= CUV(0.f
, 0.f
);
890 quadUV
.Uv1
= CUV(1.f
, 0.f
);
891 quadUV
.Uv2
= CUV(1.f
, 1.f
);
892 quadUV
.Uv3
= CUV(0.f
, 1.f
);
894 const uint nbQuads
= 128;
895 static CVertexBuffer vb
;
896 static CIndexBuffer ib
;
898 vb
.setVertexFormat(CVertexBuffer::PositionFlag
| CVertexBuffer::TexCoord0Flag
);
899 vb
.setPreferredMemory(CVertexBuffer::RAMVolatile
, false);
900 vb
.setNumVertices((nbQuads
+ 1) * 2);
903 CVertexBufferReadWrite vba
;
905 float radius
= distance
+ offcenter
;
906 float relWidth
= width
/ radius
;
907 float quadWidth
= relWidth
/ (float)nbQuads
;
908 for (uint i
= 0; i
< nbQuads
+ 1; ++i
)
912 float lineH
= -(relWidth
* 0.5f
) + quadWidth
* (float)i
;
913 float lineUV
= (float)i
/ (float)(nbQuads
);
914 float left
= sin(lineH
) * radius
;
915 float forward
= cos(lineH
) * radius
;
916 vba
.setVertexCoord(vi0
, left
, forward
- offcenter
, bottom
);
917 vba
.setTexCoord(vi0
, 0, lineUV
, 0.0f
);
918 vba
.setVertexCoord(vi1
, left
, forward
- offcenter
, top
);
919 vba
.setTexCoord(vi1
, 0, lineUV
, 1.0f
);
923 ib
.setFormat(NL_DEFAULT_INDEX_BUFFER_FORMAT
);
924 ib
.setPreferredMemory(CIndexBuffer::RAMVolatile
, false);
925 ib
.setNumIndexes(nbQuads
* 6);
928 CIndexBufferReadWrite iba
;
930 for (uint i
= 0; i
< nbQuads
; ++i
)
938 iba
.setTri(ti0
* 3, bl
, tl
, br
);
939 iba
.setTri(ti1
* 3, br
, tl
, tr
);
943 IDriver
*driver
= static_cast<CDriverUser
*>(m_Driver
)->getDriver();
944 // m_Driver->setPolygonMode(UDriver::Line);
945 driver
->activeVertexBuffer(vb
);
946 driver
->activeIndexBuffer(ib
);
947 driver
->renderTriangles(*umat
.getObjectPtr(), 0, nbQuads
* 2); //renderRawQuads(umat, 0, 128);
948 // m_Driver->setPolygonMode(UDriver::Filled);
950 // m_Driver->drawQuad(quadUV, umat);
952 m_Driver
->deleteMaterial(umat
);
955 // nldebug("Render GUI lines");
956 NL3D::UMaterial rmat = m_Driver->createMaterial();
957 rmat.setZWrite(false);
958 rmat.setZFunc(UMaterial::always); // Not nice!
959 rmat.setDoubleSided(true);
960 rmat.setColor(NLMISC::CRGBA::Red);
961 rmat.setBlend(false);
963 m_Driver->setPolygonMode(UDriver::Line);
964 driver->activeVertexBuffer(vb);
965 driver->activeIndexBuffer(ib);
966 driver->renderTriangles(*rmat.getObjectPtr(), 0, nbQuads * 2);
967 m_Driver->setPolygonMode(UDriver::Filled);
969 m_Driver->deleteMaterial(rmat);
974 /// Returns true if a render target was fully drawn
975 bool CStereoOVR::endRenderTarget()
977 // after rendering of course
978 // nlassert(m_SubStage > 1);
980 // End GUI render target
981 if (m_Driver
&& m_Stage
== 2 && (m_Driver
->getPolygonMode() == UDriver::Filled
))
983 // End GUI render target
984 nlassert(m_GUITexture
);
985 CTextureUser texNull
;
986 (static_cast<CDriverUser
*>(m_Driver
))->setRenderTarget(texNull
);
989 // End of 3D Interface pass left
990 if (m_Driver
&& m_Stage
== 5 && (m_Driver
->getPolygonMode() == UDriver::Filled
))
992 // Render 2D GUI in 3D space, assume existing camera is OK
996 // End of 3D Interface pass right
997 if (m_Driver
&& m_Stage
== 6 && (m_Driver
->getPolygonMode() == UDriver::Filled
))
999 // Render 2D GUI in 3D space, assume existing camera is OK
1002 // Recycle render target
1003 m_Driver
->getRenderTargetManager().recycleRenderTarget(m_GUITexture
);
1004 m_GUITexture
= NULL
;
1007 // End 3D scene render target
1008 if (m_Driver
&& m_Stage
== 6 && (m_Driver
->getPolygonMode() == UDriver::Filled
))
1010 nlassert(m_SceneTexture
);
1012 //nldebug("OVR: End render target");
1013 // m_Driver->endDefaultRenderTarget(NULL); // DEBUG
1015 // end render target
1016 CTextureUser texNull
;
1017 (static_cast<CDriverUser
*>(m_Driver
))->setRenderTarget(texNull
);
1020 bool fogEnabled
= m_Driver
->fogEnabled();
1021 m_Driver
->enableFog(false);
1023 // must clear everything to black (can we get a mesh to only handle the parts outside of the distortion mesh?)
1024 m_Driver
->clearRGBABuffer(CRGBA(0, 0, 0, 255));
1026 CDriverUser
*dru
= static_cast<CDriverUser
*>(m_Driver
);
1027 IDriver
*drv
= dru
->getDriver();
1031 m_Driver
->setViewport(vp
);
1032 m_Driver
->setMatrixMode2D11();
1034 for (uint eye
= 0; eye
< ovrEye_Count
; ++eye
)
1036 CMaterial
*mat
= m_UnlitMat
.getObjectPtr();
1037 mat
->setTexture(0, m_SceneTexture
->getITexture());
1038 mat
->setTexture(1, m_SceneTexture
->getITexture());
1039 mat
->setTexture(2, m_SceneTexture
->getITexture());
1040 mat
->setTexture(3, m_SceneTexture
->getITexture());
1042 //m_Driver->setPolygonMode(UDriver::Line);
1043 drv
->activeVertexBuffer(m_VB
[eye
]);
1044 drv
->activeIndexBuffer(m_IB
[eye
]);
1045 drv
->renderTriangles(*mat
, 0, m_NbTris
[eye
]);
1046 //m_Driver->setPolygonMode(UDriver::Filled);
1048 mat
->setTexture(0, NULL
);
1049 mat
->setTexture(1, NULL
);
1050 mat
->setTexture(2, NULL
);
1051 mat
->setTexture(3, NULL
);
1055 m_Driver
->enableFog(fogEnabled
);
1057 // recycle render target
1058 m_Driver
->getRenderTargetManager().recycleRenderTarget(m_SceneTexture
);
1059 m_SceneTexture
= NULL
;
1064 /*if (m_Driver && m_Stage == 6 && (m_Driver->getPolygonMode() == UDriver::Filled)) // set to 4 to turn off distortion of 2d gui
1066 nlassert(m_SceneTexture);
1068 CTextureUser texNull;
1069 (static_cast<CDriverUser *>(m_Driver))->setRenderTarget(texNull);
1070 bool fogEnabled = m_Driver->fogEnabled();
1071 m_Driver->enableFog(false);
1073 m_Driver->setMatrixMode2D11();
1074 CViewport vp = CViewport();
1075 m_Driver->setViewport(vp);
1076 uint32 width, height;
1077 m_Driver->getWindowSize(width, height);
1078 NL3D::IDriver *drvInternal = (static_cast<CDriverUser *>(m_Driver))->getDriver();
1079 NL3D::CMaterial *barrelMat = m_BarrelMat.getObjectPtr();
1080 barrelMat->setTexture(0, m_SceneTexture->getITexture());
1082 drvInternal->activePixelProgram(m_PixelProgram);
1084 float w = float(m_BarrelQuadLeft.V1.x),// / float(width),
1085 h = float(m_BarrelQuadLeft.V2.y),// / float(height),
1086 x = float(m_BarrelQuadLeft.V0.x),/// / float(width),
1087 y = float(m_BarrelQuadLeft.V0.y);// / float(height);
1089 float lensOffset = m_DevicePtr->HMDInfo.LensSeparationDistance * 0.5f;
1090 float lensShift = m_DevicePtr->HMDInfo.HScreenSize * 0.25f - lensOffset;
1091 float lensViewportShift = 4.0f * lensShift / m_DevicePtr->HMDInfo.HScreenSize;
1093 float lensCenterX = x + (w + lensViewportShift * 0.5f) * 0.5f;
1094 float lensCenterY = y + h * 0.5f;
1095 float screenCenterX = x + w * 0.5f;
1096 float screenCenterY = y + h * 0.5f;
1097 float scaleX = (w / 2);
1098 float scaleY = (h / 2);
1099 float scaleInX = (2 / w);
1100 float scaleInY = (2 / h);
1103 drvInternal->setUniform2f(IDriver::PixelProgram,
1104 m_PixelProgram->ovrIndices().LensCenter,
1105 lensCenterX, lensCenterY);
1107 drvInternal->setUniform2f(IDriver::PixelProgram,
1108 m_PixelProgram->ovrIndices().ScreenCenter,
1109 screenCenterX, screenCenterY);
1111 drvInternal->setUniform2f(IDriver::PixelProgram,
1112 m_PixelProgram->ovrIndices().Scale,
1115 drvInternal->setUniform2f(IDriver::PixelProgram,
1116 m_PixelProgram->ovrIndices().ScaleIn,
1117 scaleInX, scaleInY);
1120 drvInternal->setUniform4fv(IDriver::PixelProgram,
1121 m_PixelProgram->ovrIndices().HmdWarpParam,
1122 1, m_DevicePtr->HMDInfo.DistortionK);
1124 m_Driver->drawQuad(m_BarrelQuadLeft, m_BarrelMat);
1127 lensCenterX = x + (w - lensViewportShift * 0.5f) * 0.5f;
1128 screenCenterX = x + w * 0.5f;
1131 drvInternal->setUniform2f(IDriver::PixelProgram,
1132 m_PixelProgram->ovrIndices().LensCenter,
1133 lensCenterX, lensCenterY);
1135 drvInternal->setUniform2f(IDriver::PixelProgram,
1136 m_PixelProgram->ovrIndices().ScreenCenter,
1137 screenCenterX, screenCenterY);
1140 m_Driver->drawQuad(m_BarrelQuadRight, m_BarrelMat);
1142 drvInternal->activePixelProgram(NULL);
1143 m_Driver->enableFog(fogEnabled);
1145 // Recycle render target
1146 m_Driver->getRenderTargetManager().recycleRenderTarget(m_SceneTexture);
1147 m_SceneTexture = NULL;
1155 NLMISC::CQuat
CStereoOVR::getOrientation() const
1159 /*NLMISC::CQuat quat;
1163 if (m_OrientationCached
)
1164 return m_OrientationCache
;
1166 ovrTrackingState ts
= ovrHmd_GetTrackingState(m_DevicePtr
, ovr_GetTimeInSeconds()); // TODO: Predict forward
1167 if (ts
.StatusFlags
& ovrStatus_OrientationTracked
)
1169 // get just the orientation
1170 ovrQuatf quatovr
= ts
.HeadPose
.ThePose
.Orientation
;
1171 NLMISC::CMatrix coordsys
;
1173 1.0f
, 0.0f
, 0.0f
, 0.0f
,
1174 0.0f
, 0.0f
, -1.0f
, 0.0f
,
1175 0.0f
, 1.0f
, 0.0f
, 0.0f
,
1176 0.0f
, 0.0f
, 0.0f
, 1.0f
,
1179 NLMISC::CMatrix matovr
;
1180 matovr
.setRot(NLMISC::CQuat(quatovr
.x
, quatovr
.y
, quatovr
.z
, quatovr
.w
));
1181 NLMISC::CMatrix matr
;
1182 // matr.rotateZ(NLMISC::Pi); // uncomment when backwards ...
1183 matr
.rotateX(NLMISC::Pi
* 0.5f
); // fix this properly... :) (note: removing this allows you to use rift while lying down)
1184 NLMISC::CMatrix matnel
= matr
* matovr
* coordsys
;
1185 NLMISC::CQuat finalquat
= matnel
.getRot();
1186 m_OrientationCache
= finalquat
;
1187 m_OrientationCached
= true;
1193 nlwarning("OVR: No orientation returned");
1194 // return old orientation
1195 m_OrientationCached
= true;
1196 return m_OrientationCache
;
1201 void CStereoOVR::getInterface2DShift(uint cid
, float &x
, float &y
, float distance
) const
1206 void CStereoOVR::setEyePosition(const NLMISC::CVector
&v
)
1211 const NLMISC::CVector
&CStereoOVR::getEyePosition() const
1213 return m_EyePosition
;
1216 void CStereoOVR::setScale(float s
)
1218 m_EyePosition
= m_EyePosition
* (s
/ m_Scale
);
1224 void CStereoOVR::listDevices(std::vector
<CStereoDeviceInfo
> &devicesOut
)
1226 if (!s_StereoOVRSystem
.Init())
1230 uint hmdDetect
= ovrHmd_Detect();
1231 nldebug("OVR: Detected %u HMDs", hmdDetect
);
1233 for (uint i
= 0; i
< hmdDetect
; ++i
)
1235 devicesOut
.resize(devicesOut
.size() + 1);
1236 CStereoDeviceInfo
&deviceInfoOut
= devicesOut
[devicesOut
.size() - 1];
1237 ovrHmd hmd
= ovrHmd_Create(i
);
1238 CStereoOVRDeviceFactory
*factory
= new CStereoOVRDeviceFactory();
1239 factory
->DetectId
= s_DetectId
;
1240 factory
->DeviceIndex
= i
;
1241 factory
->DebugDevice
= false;
1242 deviceInfoOut
.Factory
= factory
;
1243 deviceInfoOut
.Class
= CStereoDeviceInfo::StereoHMD
;
1244 deviceInfoOut
.Library
= CStereoDeviceInfo::OVR
;
1245 deviceInfoOut
.Manufacturer
= hmd
->Manufacturer
;
1246 deviceInfoOut
.ProductName
= hmd
->ProductName
;
1247 deviceInfoOut
.AllowAuto
= true;
1248 deviceInfoOut
.Serial
= hmd
->SerialNumber
;
1249 ovrHmd_Destroy(hmd
);
1255 devicesOut
.resize(devicesOut
.size() + 1);
1256 CStereoDeviceInfo
&deviceInfoOut
= devicesOut
[devicesOut
.size() - 1];
1257 ovrHmd hmd
= ovrHmd_CreateDebug(ovrHmd_DK1
);
1258 CStereoOVRDeviceFactory
*factory
= new CStereoOVRDeviceFactory();
1259 factory
->DetectId
= s_DetectId
;
1260 factory
->DebugDevice
= true;
1261 factory
->DebugDeviceType
= ovrHmd_DK1
;
1262 deviceInfoOut
.Factory
= factory
;
1263 deviceInfoOut
.Class
= CStereoDeviceInfo::StereoHMD
;
1264 deviceInfoOut
.Library
= CStereoDeviceInfo::OVR
;
1265 deviceInfoOut
.Manufacturer
= hmd
->Manufacturer
;
1266 deviceInfoOut
.ProductName
= hmd
->ProductName
;
1267 deviceInfoOut
.AllowAuto
= false;
1268 deviceInfoOut
.Serial
= "OVR-DK1-DEBUG";
1269 ovrHmd_Destroy(hmd
);
1273 devicesOut
.resize(devicesOut
.size() + 1);
1274 CStereoDeviceInfo
&deviceInfoOut
= devicesOut
[devicesOut
.size() - 1];
1275 ovrHmd hmd
= ovrHmd_CreateDebug(ovrHmd_DK2
);
1276 CStereoOVRDeviceFactory
*factory
= new CStereoOVRDeviceFactory();
1277 factory
->DetectId
= s_DetectId
;
1278 factory
->DebugDevice
= true;
1279 factory
->DebugDeviceType
= ovrHmd_DK2
;
1280 deviceInfoOut
.Factory
= factory
;
1281 deviceInfoOut
.Class
= CStereoDeviceInfo::StereoHMD
;
1282 deviceInfoOut
.Library
= CStereoDeviceInfo::OVR
;
1283 deviceInfoOut
.Manufacturer
= hmd
->Manufacturer
;
1284 deviceInfoOut
.ProductName
= hmd
->ProductName
;
1285 deviceInfoOut
.AllowAuto
= false;
1286 deviceInfoOut
.Serial
= "OVR-DK2-DEBUG";
1287 ovrHmd_Destroy(hmd
);
1292 bool CStereoOVR::isLibraryInUse()
1294 nlassert(s_DeviceCounter
>= 0);
1295 return s_DeviceCounter
> 0;
1298 void CStereoOVR::releaseLibrary()
1300 nlassert(s_DeviceCounter
== 0);
1301 s_StereoOVRSystem
.Release();
1304 bool CStereoOVR::isDeviceCreated()
1306 return m_DevicePtr
!= NULL
;
1309 } /* namespace NL3D */
1311 #endif /* HAVE_LIBOVR */