Linux multi-monitor fullscreen support
[ryzomcore.git] / nel / src / 3d / stereo_ovr_04.cpp
blob1d0c8228405777a755730603d3b51314acde3814
1 /**
2 * \file stereo_ovr.cpp
3 * \brief CStereoOVR
4 * \date 2014-08-04 16:21GMT
5 * \author Jan Boon (Kaetemi)
6 * CStereoOVR
7 */
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/>.
24 //
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
28 // combination.
29 //
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.
41 #ifdef HAVE_LIBOVR
43 #include "std3d.h"
44 #include "nel/3d/stereo_ovr_04.h"
46 // STL includes
47 #include <sstream>
49 // External includes
50 #define OVR_NO_STDINT
51 #include <OVR.h>
53 // NeL includes
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"
63 // Project includes
65 using namespace std;
66 // using namespace NLMISC;
68 #ifdef DEBUG_NEW
69 #define new DEBUG_NEW
70 #endif
72 namespace NL3D {
74 namespace {
76 #include "stereo_ovr_04_program.h"
78 class CStereoOVRSystem
80 public:
81 CStereoOVRSystem() : m_InitOk(false)
86 ~CStereoOVRSystem()
88 if (m_InitOk)
90 nlwarning("OVR: Not all resources were released before exit");
91 Release();
95 bool Init()
97 if (!m_InitOk)
99 nldebug("OVR: Initialize");
100 m_InitOk = ovr_Initialize();
101 nlassert(m_InitOk);
104 return m_InitOk;
107 void Release()
109 if (m_InitOk)
111 nldebug("OVR: Release");
112 ovr_Shutdown();
113 m_InitOk = false;
117 private:
118 bool m_InitOk;
122 CStereoOVRSystem s_StereoOVRSystem;
124 sint s_DeviceCounter = 0;
125 uint s_DetectId = 0;
129 class CStereoOVRDeviceFactory : public IStereoDeviceFactory
131 public:
132 uint DeviceIndex;
133 uint DetectId;
135 bool DebugDevice;
136 ovrHmdType DebugDeviceType;
138 IStereoDisplay *createDevice() const
140 CStereoOVR *stereo = new CStereoOVR(this);
141 if (stereo->isDeviceCreated())
142 return stereo;
143 delete stereo;
144 return NULL;
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;
156 vec.x += 0.5f;
157 vec.y *= 2.0f;
159 vec.x = 1.0f - vec.x;
161 return vec;
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");
176 return;
179 m_DebugDevice = factory->DebugDevice;
180 if (factory->DebugDevice) m_DevicePtr = ovrHmd_CreateDebug(factory->DebugDeviceType);
181 else m_DevicePtr = ovrHmd_Create(factory->DeviceIndex);
183 if (!m_DevicePtr)
185 nlwarning("OVR: Device not created");
186 return;
189 ++s_DeviceCounter;
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);
206 m_DevicePtr = NULL;
207 --s_DeviceCounter;
208 return;
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;
247 // store data
248 m_EyeViewAdjustX[eye] = -eyeRenderDesc[eye].ViewAdjust.x;
250 // setup viewport
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
279 -fov.DownTan,
280 fov.UpTan, // DEBUG: If renders shifted up or down, swap down and up
281 1.0f, // dummy
282 100.f, // dummy
283 true);
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
291 &meshData);
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);
301 // chroma bugfix
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;
312 m_VB[eye].lock(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);
330 NLMISC::CRGBA color;
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;
343 m_IB[eye].lock(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]);
353 // set tri count
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);
367 // DEBUG EARLY EXIT
368 /*nldebug("OVR: Early exit");
369 ovrHmd_Destroy(m_DevicePtr);
370 m_DevicePtr = NULL;
371 --s_DeviceCounter;*/
374 CStereoOVR::~CStereoOVR()
376 if (m_AttachedDisplay)
378 detachFromDisplay();
381 if (!m_UnlitMat.empty())
383 m_Driver->deleteMaterial(m_UnlitMat);
386 m_Driver = NULL;
388 if (m_DevicePtr)
390 ovrHmd_Destroy(m_DevicePtr);
391 m_DevicePtr = NULL;
392 --s_DeviceCounter;
396 void CStereoOVR::setDriver(NL3D::UDriver *driver)
398 m_Driver = 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)
440 if (m_DevicePtr)
442 width = m_DevicePtr->Resolution.w;
443 height = m_DevicePtr->Resolution.h;
444 return true;
446 return false;
449 bool CStereoOVR::attachToDisplay()
451 nldebug("OVR: Attach to display '%s'", m_DevicePtr->DisplayDeviceName);
453 if (m_DebugDevice)
454 return false;
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!");
472 else
473 #endif
475 nldebug("OVR: Extended Rift");
476 UDriver::CMode mode;
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];
508 return;*/
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,
517 true);
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,
526 true);
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,
535 true);
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
564 case 0:
565 m_Stage += 2;
566 m_SubStage = 0;
567 // stage 2:
568 // draw interface 2d (onto render target)
569 return true;
570 case 2:
571 ++m_Stage;
572 m_SubStage = 0;
573 // stage 3:
574 // (initBloom)
575 // clear buffer
576 // draw scene left
577 return true;
578 case 3:
579 ++m_Stage;
580 m_SubStage = 0;
581 // stage 4:
582 // draw scene right
583 return true;
584 case 4:
585 ++m_Stage;
586 m_SubStage = 0;
587 // stage 5:
588 // (endBloom)
589 // draw interface 3d left
590 return true;
591 case 5:
592 ++m_Stage;
593 m_SubStage = 0;
594 // stage 6:
595 // draw interface 3d right
596 return true;
597 /*case 6:
598 ++m_Stage;
599 m_SubStage = 0;
600 // stage 7:
601 // (endInterfacesDisplayBloom)
602 // draw interface 2d left
603 return true;
604 case 7:
605 ++m_Stage;
606 m_SubStage = 0;
607 // stage 8:
608 // draw interface 2d right
609 return true;*/
610 case 6:
611 m_Stage = 0;
612 m_SubStage = 0;
613 // present
614 m_OrientationCached = false;
615 return false;
618 else
620 switch (m_Stage)
622 case 0:
623 ++m_Stage;
624 m_SubStage = 0;
625 return true;
626 case 1:
627 m_Stage = 0;
628 m_SubStage = 0;
629 return false;
632 nlerror("Invalid stage");
633 m_Stage = 0;
634 m_SubStage = 0;
635 m_OrientationCached = false;
636 return 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
662 CMatrix translate;
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());
672 else
674 // camera->setTransformMode(NL3D::UTransformable::DirectMatrix);
675 camera->setMatrix(mat);
679 bool CStereoOVR::wantClear()
681 switch (m_Stage)
683 case 3:
684 m_SubStage = 1;
685 return true;
687 return m_Driver->getPolygonMode() != UDriver::Filled;
690 bool CStereoOVR::wantScene()
692 switch (m_Stage)
694 case 3:
695 case 4:
696 m_SubStage = 2;
697 return true;
699 return m_Driver->getPolygonMode() != UDriver::Filled;
702 bool CStereoOVR::wantSceneEffects()
704 switch (m_Stage)
706 case 4:
707 return true;
709 return m_Driver->getPolygonMode() != UDriver::Filled;
712 bool CStereoOVR::wantInterface3D()
714 switch (m_Stage)
716 case 5:
717 case 6:
718 m_SubStage = 3;
719 return true;
721 return m_Driver->getPolygonMode() != UDriver::Filled;
724 bool CStereoOVR::wantInterface2D()
726 switch (m_Stage)
728 case 2:
729 m_SubStage = 4;
730 return true;
732 return m_Driver->getPolygonMode() != UDriver::Filled;
735 bool CStereoOVR::isSceneFirst()
737 switch (m_Stage)
739 case 3:
740 return true;
741 case 4:
742 return false;
744 return m_Driver->getPolygonMode() != UDriver::Filled;
747 bool CStereoOVR::isSceneLast()
749 switch (m_Stage)
751 case 3:
752 return false;
753 case 4:
754 return true;
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));
774 return true;
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);
783 return true;
784 /*nldebug("OVR: Begin render target");*/
785 //m_Driver->beginDefaultRenderTarget(m_RenderTargetWidth, m_RenderTargetHeight); // DEBUG
786 //return true;
789 return false;
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);
809 mat.setBlend(false);
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);
821 mat.setBlend(false);
822 NLMISC::CLine line;
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();
857 umat.initUnlit();
858 umat.setColor(NLMISC::CRGBA::White);
859 umat.setDoubleSided(true);
860 umat.setBlend(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());
870 // user options
871 float scale = 1.0f;
872 float distance = 1.5f;
873 float offcenter = 0.75f;
875 float height = scale * distance * 2.0f;
877 uint32 winw, winh;
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;
904 vb.lock(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)
910 uint vi0 = i * 2;
911 uint vi1 = vi0 + 1;
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;
929 ib.lock(iba);
930 for (uint i = 0; i < nbQuads; ++i)
932 uint ti0 = i * 2;
933 uint ti1 = ti0 + 1;
934 uint bl = ti0;
935 uint tl = ti0 + 1;
936 uint br = ti0 + 2;
937 uint tr = ti0 + 3;
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
993 renderGUI();
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
1000 renderGUI();
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);
1019 // backup
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();
1029 // set matrix mode
1030 CViewport vp;
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);
1054 // restore
1055 m_Driver->enableFog(fogEnabled);
1057 // recycle render target
1058 m_Driver->getRenderTargetManager().recycleRenderTarget(m_SceneTexture);
1059 m_SceneTexture = NULL;
1061 return true;
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,
1113 scaleX, scaleY);
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);
1126 x = w;
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;
1149 return true;
1152 return false;
1155 NLMISC::CQuat CStereoOVR::getOrientation() const
1157 // broken
1159 /*NLMISC::CQuat quat;
1160 quat.identity();
1161 return 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;
1172 float csys[] = {
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,
1178 coordsys.set(csys);
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;
1188 return finalquat;
1190 else
1192 if (!m_DebugDevice)
1193 nlwarning("OVR: No orientation returned");
1194 // return old orientation
1195 m_OrientationCached = true;
1196 return m_OrientationCache;
1200 /// Get GUI shift
1201 void CStereoOVR::getInterface2DShift(uint cid, float &x, float &y, float distance) const
1206 void CStereoOVR::setEyePosition(const NLMISC::CVector &v)
1208 m_EyePosition = 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);
1219 m_Scale = s;
1224 void CStereoOVR::listDevices(std::vector<CStereoDeviceInfo> &devicesOut)
1226 if (!s_StereoOVRSystem.Init())
1227 return;
1229 ++s_DetectId;
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);
1252 #if !FINAL_VERSION
1253 // Debug DK1
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);
1271 // Debug DK2
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);
1289 #endif
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 */
1313 /* end of file */