Merge branch 'ryzom/ark-features' into main/gingo-test
[ryzomcore.git] / nel / src / 3d / stereo_libvr.cpp
blobe317f0b66d27cc5b05c800b4e2cd316ac6247d47
1 /**
2 * \file stereo_libvr.cpp
3 * \brief CStereoLibVR
4 * \date 2013-08-19 19:17MT
5 * \author Thibaut Girka (ThibG)
6 * CStereoLibVR
7 */
9 // NeL - MMORPG Framework <https://wiki.ryzom.dev/>
10 // Copyright (C) 2013 Thibaut GIRKA (ThibG) <thib@sitedethib.com>
12 // This source file has been modified by the following contributors:
13 // Copyright (C) 2014 Jan BOON (Kaetemi) <jan.boon@kaetemi.be>
15 // This program is free software: you can redistribute it and/or modify
16 // it under the terms of the GNU Affero General Public License as
17 // published by the Free Software Foundation, either version 3 of the
18 // License, or (at your option) any later version.
20 // This program is distributed in the hope that it will be useful,
21 // but WITHOUT ANY WARRANTY; without even the implied warranty of
22 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23 // GNU Affero General Public License for more details.
25 // You should have received a copy of the GNU Affero General Public License
26 // along with this program. If not, see <http://www.gnu.org/licenses/>.
28 #ifdef HAVE_LIBVR
30 #include "std3d.h"
31 #include "nel/misc/time_nl.h"
32 #include "nel/3d/stereo_libvr.h"
34 // STL includes
35 #include <sstream>
37 // External includes
38 extern "C" {
39 #include <hmd.h>
42 // NeL includes
43 // #include <nel/misc/debug.h>
44 #include "nel/3d/u_camera.h"
45 #include "nel/3d/u_driver.h"
46 #include "nel/3d/material.h"
47 #include "nel/3d/texture_bloom.h"
48 #include "nel/3d/texture_user.h"
49 #include "nel/3d/driver_user.h"
50 #include "nel/3d/u_texture.h"
52 // Project includes
54 using namespace std;
55 // using namespace NLMISC;
57 #ifdef DEBUG_NEW
58 #define new DEBUG_NEW
59 #endif
61 namespace NL3D {
63 extern const char *g_StereoOVR_fp40; //TODO: what?
64 extern const char *g_StereoOVR_arbfp1; //TODO: what?
65 extern const char *g_StereoOVR_ps_2_0; //TODO: what?
67 namespace {
68 sint s_DeviceCounter = 0;
71 class CStereoLibVRDeviceHandle : public IStereoDeviceFactory
73 public:
74 // fixme: virtual destructor???
75 IStereoDisplay *createDevice() const
77 CStereoLibVR *stereo = new CStereoLibVR(this);
78 if (stereo->isDeviceCreated())
79 return stereo;
80 delete stereo;
81 return NULL;
85 class CStereoLibVRDevicePtr
87 public:
88 struct hmd *HMDDevice;
89 struct display_info HMDInfo;
90 float InterpupillaryDistance;
93 CStereoLibVR::CStereoLibVR(const CStereoLibVRDeviceHandle *handle) : m_Stage(0), m_SubStage(0), m_OrientationCached(false), m_Driver(NULL), m_BarrelTexU(NULL), m_PixelProgram(NULL), m_EyePosition(0.0f, 0.09f, 0.15f), m_Scale(1.0f)
95 struct stereo_config st_conf;
97 ++s_DeviceCounter;
98 // For now, LibVR doesn't support multiple devices...
99 m_DevicePtr = new CStereoLibVRDevicePtr();
100 m_DevicePtr->HMDDevice = hmd_open_first(0);
101 m_DevicePtr->InterpupillaryDistance = 0.0647; //TODO
103 if (m_DevicePtr->HMDDevice)
105 hmd_get_display_info(m_DevicePtr->HMDDevice, &m_DevicePtr->HMDInfo);
106 hmd_get_stereo_config(m_DevicePtr->HMDDevice, &st_conf);
107 nldebug("LibVR: HScreenSize: %f, VScreenSize: %f", m_DevicePtr->HMDInfo.h_screen_size, m_DevicePtr->HMDInfo.v_screen_size);
108 nldebug("LibVR: VScreenCenter: %f", m_DevicePtr->HMDInfo.v_center);
109 nldebug("LibVR: EyeToScreenDistance: %f", m_DevicePtr->HMDInfo.eye_to_screen[0]);
110 nldebug("LibVR: LensSeparationDistance: %f", m_DevicePtr->HMDInfo.lens_separation);
111 nldebug("LibVR: HResolution: %i, VResolution: %i", m_DevicePtr->HMDInfo.h_resolution, m_DevicePtr->HMDInfo.v_resolution);
112 nldebug("LibVR: DistortionK[0]: %f, DistortionK[1]: %f", m_DevicePtr->HMDInfo.distortion_k[0], m_DevicePtr->HMDInfo.distortion_k[1]);
113 nldebug("LibVR: DistortionK[2]: %f, DistortionK[3]: %f", m_DevicePtr->HMDInfo.distortion_k[2], m_DevicePtr->HMDInfo.distortion_k[3]);
114 nldebug("LibVR: Scale: %f", st_conf.distort.scale);
115 m_LeftViewport.init(0.f, 0.f, 0.5f, 1.0f);
116 m_RightViewport.init(0.5f, 0.f, 0.5f, 1.0f);
120 CStereoLibVR::~CStereoLibVR()
122 if (!m_BarrelMat.empty())
124 m_BarrelMat.getObjectPtr()->setTexture(0, NULL);
125 m_Driver->deleteMaterial(m_BarrelMat);
127 delete m_BarrelTexU;
128 m_BarrelTexU = NULL;
129 m_BarrelTex = NULL; // CSmartPtr
131 delete m_PixelProgram;
132 m_PixelProgram = NULL;
134 m_Driver = NULL;
136 if (m_DevicePtr->HMDDevice)
137 hmd_close(m_DevicePtr->HMDDevice);
139 delete m_DevicePtr;
140 m_DevicePtr = NULL;
142 --s_DeviceCounter;
145 void CStereoLibVR::setDriver(NL3D::UDriver *driver)
147 nlassert(!m_PixelProgram);
149 NL3D::IDriver *drvInternal = (static_cast<CDriverUser *>(driver))->getDriver();
150 if (drvInternal->supportPixelProgram(CPixelProgram::fp40) && drvInternal->supportBloomEffect() && drvInternal->supportNonPowerOfTwoTextures())
152 nldebug("VR: fp40");
153 m_PixelProgram = new CPixelProgram(g_StereoOVR_fp40);
155 else if (drvInternal->supportPixelProgram(CPixelProgram::arbfp1) && drvInternal->supportBloomEffect() && drvInternal->supportNonPowerOfTwoTextures())
157 nldebug("VR: arbfp1");
158 m_PixelProgram = new CPixelProgram(g_StereoOVR_arbfp1);
160 else if (drvInternal->supportPixelProgram(CPixelProgram::ps_2_0))
162 nldebug("VR: ps_2_0");
163 m_PixelProgram = new CPixelProgram(g_StereoOVR_ps_2_0);
166 if (m_PixelProgram)
168 m_Driver = driver;
170 m_BarrelTex = new CTextureBloom(); // lol bloom
171 m_BarrelTex->setRenderTarget(true);
172 m_BarrelTex->setReleasable(false);
173 m_BarrelTex->resize(m_DevicePtr->HMDInfo.h_resolution, m_DevicePtr->HMDInfo.v_resolution);
174 m_BarrelTex->setFilterMode(ITexture::Linear, ITexture::LinearMipMapOff);
175 m_BarrelTex->setWrapS(ITexture::Clamp);
176 m_BarrelTex->setWrapT(ITexture::Clamp);
177 drvInternal->setupTexture(*m_BarrelTex);
178 m_BarrelTexU = new CTextureUser(m_BarrelTex);
180 m_BarrelMat = m_Driver->createMaterial();
181 m_BarrelMat.initUnlit();
182 m_BarrelMat.setColor(CRGBA::White);
183 m_BarrelMat.setBlend (false);
184 m_BarrelMat.setAlphaTest (false);
185 NL3D::CMaterial *barrelMat = m_BarrelMat.getObjectPtr();
186 barrelMat->setShader(NL3D::CMaterial::PostProcessing);
187 barrelMat->setBlendFunc(CMaterial::one, CMaterial::zero);
188 barrelMat->setZWrite(false);
189 barrelMat->setZFunc(CMaterial::always);
190 barrelMat->setDoubleSided(true);
191 barrelMat->setTexture(0, m_BarrelTex);
193 m_BarrelQuadLeft.V0 = CVector(0.f, 0.f, 0.5f);
194 m_BarrelQuadLeft.V1 = CVector(0.5f, 0.f, 0.5f);
195 m_BarrelQuadLeft.V2 = CVector(0.5f, 1.f, 0.5f);
196 m_BarrelQuadLeft.V3 = CVector(0.f, 1.f, 0.5f);
198 m_BarrelQuadRight.V0 = CVector(0.5f, 0.f, 0.5f);
199 m_BarrelQuadRight.V1 = CVector(1.f, 0.f, 0.5f);
200 m_BarrelQuadRight.V2 = CVector(1.f, 1.f, 0.5f);
201 m_BarrelQuadRight.V3 = CVector(0.5f, 1.f, 0.5f);
203 nlassert(!drvInternal->isTextureRectangle(m_BarrelTex)); // not allowed
205 m_BarrelQuadLeft.Uv0 = CUV(0.f, 0.f);
206 m_BarrelQuadLeft.Uv1 = CUV(0.5f, 0.f);
207 m_BarrelQuadLeft.Uv2 = CUV(0.5f, 1.f);
208 m_BarrelQuadLeft.Uv3 = CUV(0.f, 1.f);
210 m_BarrelQuadRight.Uv0 = CUV(0.5f, 0.f);
211 m_BarrelQuadRight.Uv1 = CUV(1.f, 0.f);
212 m_BarrelQuadRight.Uv2 = CUV(1.f, 1.f);
213 m_BarrelQuadRight.Uv3 = CUV(0.5f, 1.f);
215 else
217 nlwarning("VR: No pixel program support");
221 bool CStereoLibVR::getScreenResolution(uint &width, uint &height)
223 width = m_DevicePtr->HMDInfo.h_resolution;
224 height = m_DevicePtr->HMDInfo.v_resolution;
225 return true;
228 void CStereoLibVR::initCamera(uint cid, const NL3D::UCamera *camera)
230 struct stereo_config st_conf;
231 hmd_get_stereo_config(m_DevicePtr->HMDDevice, &st_conf);
233 float ar = st_conf.proj.aspect_ratio;
234 float fov = st_conf.proj.yfov;
235 m_LeftFrustum[cid].initPerspective(fov, ar, camera->getFrustum().Near, camera->getFrustum().Far);
236 m_RightFrustum[cid] = m_LeftFrustum[cid];
238 float projectionCenterOffset = st_conf.proj.projection_offset * 0.5 * (m_LeftFrustum[cid].Right - m_LeftFrustum[cid].Left);
239 nldebug("LibVR: projectionCenterOffset = %f", projectionCenterOffset);
241 m_LeftFrustum[cid].Left -= projectionCenterOffset;
242 m_LeftFrustum[cid].Right -= projectionCenterOffset;
243 m_RightFrustum[cid].Left += projectionCenterOffset;
244 m_RightFrustum[cid].Right += projectionCenterOffset;
246 // TODO: Clipping frustum should also take into account the IPD
247 m_ClippingFrustum[cid] = m_LeftFrustum[cid];
248 m_ClippingFrustum[cid].Left = min(m_LeftFrustum[cid].Left, m_RightFrustum[cid].Left);
249 m_ClippingFrustum[cid].Right = max(m_LeftFrustum[cid].Right, m_RightFrustum[cid].Right);
252 /// Get the frustum to use for clipping
253 void CStereoLibVR::getClippingFrustum(uint cid, NL3D::UCamera *camera) const
255 camera->setFrustum(m_ClippingFrustum[cid]);
258 void CStereoLibVR::updateCamera(uint cid, const NL3D::UCamera *camera)
260 if (camera->getFrustum().Near != m_LeftFrustum[cid].Near
261 || camera->getFrustum().Far != m_LeftFrustum[cid].Far)
262 CStereoLibVR::initCamera(cid, camera);
263 m_CameraMatrix[cid] = camera->getMatrix();
266 bool CStereoLibVR::nextPass()
268 // Do not allow weird stuff.
269 uint32 width, height;
270 m_Driver->getWindowSize(width, height);
271 nlassert(width == m_DevicePtr->HMDInfo.h_resolution);
272 nlassert(height == m_DevicePtr->HMDInfo.v_resolution);
274 if (m_Driver->getPolygonMode() == UDriver::Filled)
276 switch (m_Stage)
278 case 0:
279 ++m_Stage;
280 m_SubStage = 0;
281 // stage 1:
282 // (initBloom)
283 // clear buffer
284 // draw scene left
285 return true;
286 case 1:
287 ++m_Stage;
288 m_SubStage = 0;
289 // stage 2:
290 // draw scene right
291 return true;
292 case 2:
293 ++m_Stage;
294 m_SubStage = 0;
295 // stage 3:
296 // (endBloom)
297 // draw interface 3d left
298 return true;
299 case 3:
300 ++m_Stage;
301 m_SubStage = 0;
302 // stage 4:
303 // draw interface 3d right
304 return true;
305 case 4:
306 ++m_Stage;
307 m_SubStage = 0;
308 // stage 5:
309 // (endInterfacesDisplayBloom)
310 // draw interface 2d left
311 return true;
312 case 5:
313 ++m_Stage;
314 m_SubStage = 0;
315 // stage 6:
316 // draw interface 2d right
317 return true;
318 case 6:
319 m_Stage = 0;
320 m_SubStage = 0;
321 // present
322 m_OrientationCached = false;
323 return false;
326 else
328 switch (m_Stage)
330 case 0:
331 ++m_Stage;
332 m_SubStage = 0;
333 return true;
334 case 1:
335 m_Stage = 0;
336 m_SubStage = 0;
337 return false;
340 nlerror("Invalid stage");
341 m_Stage = 0;
342 m_SubStage = 0;
343 m_OrientationCached = false;
344 return false;
347 const NL3D::CViewport &CStereoLibVR::getCurrentViewport() const
349 if (m_Stage % 2) return m_LeftViewport;
350 else return m_RightViewport;
353 const NL3D::CFrustum &CStereoLibVR::getCurrentFrustum(uint cid) const
355 if (m_Stage % 2) return m_LeftFrustum[cid];
356 else return m_RightFrustum[cid];
359 void CStereoLibVR::getCurrentFrustum(uint cid, NL3D::UCamera *camera) const
361 if (m_Stage % 2) camera->setFrustum(m_LeftFrustum[cid]);
362 else camera->setFrustum(m_RightFrustum[cid]);
365 void CStereoLibVR::getCurrentMatrix(uint cid, NL3D::UCamera *camera) const
367 CMatrix translate;
368 if (m_Stage % 2) translate.translate(CVector((m_DevicePtr->InterpupillaryDistance * m_Scale) * -0.5f, 0.f, 0.f));
369 else translate.translate(CVector((m_DevicePtr->InterpupillaryDistance * m_Scale) * 0.5f, 0.f, 0.f));
370 CMatrix mat = m_CameraMatrix[cid] * translate;
371 if (camera->getTransformMode() == NL3D::UTransformable::RotQuat)
373 camera->setPos(mat.getPos());
374 camera->setRotQuat(mat.getRot());
376 else
378 // camera->setTransformMode(NL3D::UTransformable::DirectMatrix);
379 camera->setMatrix(mat);
383 bool CStereoLibVR::wantClear()
385 switch (m_Stage)
387 case 1:
388 m_SubStage = 1;
389 return true;
391 return m_Driver->getPolygonMode() != UDriver::Filled;
394 bool CStereoLibVR::wantScene()
396 switch (m_Stage)
398 case 1:
399 case 2:
400 m_SubStage = 2;
401 return true;
403 return m_Driver->getPolygonMode() != UDriver::Filled;
406 bool CStereoLibVR::wantInterface3D()
408 switch (m_Stage)
410 case 3:
411 case 4:
412 m_SubStage = 3;
413 return true;
415 return m_Driver->getPolygonMode() != UDriver::Filled;
418 bool CStereoLibVR::wantInterface2D()
420 switch (m_Stage)
422 case 5:
423 case 6:
424 m_SubStage = 4;
425 return true;
427 return m_Driver->getPolygonMode() != UDriver::Filled;
431 /// Returns non-NULL if a new render target was set
432 bool CStereoLibVR::beginRenderTarget()
434 // render target always set before driver clear
435 // nlassert(m_SubStage <= 1);
436 if (m_Driver && m_Stage == 1 && (m_Driver->getPolygonMode() == UDriver::Filled))
438 static_cast<CDriverUser *>(m_Driver)->setRenderTarget(*m_BarrelTexU, 0, 0, 0, 0);
439 return true;
441 return false;
444 /// Returns true if a render target was fully drawn
445 bool CStereoLibVR::endRenderTarget()
447 // after rendering of course
448 // nlassert(m_SubStage > 1);
449 if (m_Driver && m_Stage == 6 && (m_Driver->getPolygonMode() == UDriver::Filled)) // set to 4 to turn off distortion of 2d gui
451 struct stereo_config st_conf;
452 hmd_get_stereo_config(m_DevicePtr->HMDDevice, &st_conf);
453 CTextureUser cu;
454 (static_cast<CDriverUser *>(m_Driver))->setRenderTarget(cu);
455 bool fogEnabled = m_Driver->fogEnabled();
456 m_Driver->enableFog(false);
458 m_Driver->setMatrixMode2D11();
459 CViewport vp = CViewport();
460 m_Driver->setViewport(vp);
461 uint32 width, height;
462 m_Driver->getWindowSize(width, height);
463 NL3D::IDriver *drvInternal = (static_cast<CDriverUser *>(m_Driver))->getDriver();
464 NL3D::CMaterial *barrelMat = m_BarrelMat.getObjectPtr();
465 barrelMat->setTexture(0, m_BarrelTex);
466 drvInternal->activePixelProgram(m_PixelProgram);
468 float w = float(m_BarrelQuadLeft.V1.x),// / float(width),
469 h = float(m_BarrelQuadLeft.V2.y),// / float(height),
470 x = float(m_BarrelQuadLeft.V0.x),/// / float(width),
471 y = float(m_BarrelQuadLeft.V0.y);// / float(height);
473 //TODO: stereo_config stuff
474 float lensViewportShift = st_conf.proj.projection_offset;
476 float lensCenterX = x + (w + lensViewportShift * 0.5f) * 0.5f;
477 float lensCenterY = y + h * 0.5f;
478 float screenCenterX = x + w * 0.5f;
479 float screenCenterY = y + h * 0.5f;
480 float scaleX = (w / 2 / st_conf.distort.scale);
481 float scaleY = (h / 2 / st_conf.distort.scale);
482 float scaleInX = (2 / w);
483 float scaleInY = (2 / h);
484 drvInternal->setPixelProgramConstant(0, lensCenterX, lensCenterY, 0.f, 0.f);
485 drvInternal->setPixelProgramConstant(1, screenCenterX, screenCenterY, 0.f, 0.f);
486 drvInternal->setPixelProgramConstant(2, scaleX, scaleY, 0.f, 0.f);
487 drvInternal->setPixelProgramConstant(3, scaleInX, scaleInY, 0.f, 0.f);
488 drvInternal->setPixelProgramConstant(4, 1, st_conf.distort.distortion_k);
491 m_Driver->drawQuad(m_BarrelQuadLeft, m_BarrelMat);
493 x = w;
494 lensCenterX = x + (w - lensViewportShift * 0.5f) * 0.5f;
495 screenCenterX = x + w * 0.5f;
496 drvInternal->setPixelProgramConstant(0, lensCenterX, lensCenterY, 0.f, 0.f);
497 drvInternal->setPixelProgramConstant(1, screenCenterX, screenCenterY, 0.f, 0.f);
499 m_Driver->drawQuad(m_BarrelQuadRight, m_BarrelMat);
501 drvInternal->activePixelProgram(NULL);
502 m_Driver->enableFog(fogEnabled);
504 return true;
506 return false;
509 NLMISC::CQuat CStereoLibVR::getOrientation() const
511 if (m_OrientationCached)
512 return m_OrientationCache;
514 unsigned int t = NLMISC::CTime::getLocalTime();
515 hmd_update(m_DevicePtr->HMDDevice, &t);
517 float quat[4];
518 hmd_get_rotation(m_DevicePtr->HMDDevice, quat);
519 NLMISC::CMatrix coordsys;
520 float csys[] = {
521 1.0f, 0.0f, 0.0f, 0.0f,
522 0.0f, 0.0f, -1.0f, 0.0f,
523 0.0f, 1.0f, 0.0f, 0.0f,
524 0.0f, 0.0f, 0.0f, 1.0f,
526 coordsys.set(csys);
527 NLMISC::CMatrix matovr;
528 matovr.setRot(NLMISC::CQuat(quat[1], quat[2], quat[3], quat[0]));
529 NLMISC::CMatrix matr;
530 matr.rotateX(NLMISC::Pi * 0.5f); // fix this properly... :) (note: removing this allows you to use rift while lying down)
531 NLMISC::CMatrix matnel = matr * matovr * coordsys;
532 NLMISC::CQuat finalquat = matnel.getRot();
533 m_OrientationCache = finalquat;
534 m_OrientationCached = true;
535 return finalquat;
538 /// Get GUI shift
539 void CStereoLibVR::getInterface2DShift(uint cid, float &x, float &y, float distance) const
541 #if 0
543 // todo: take into account m_EyePosition
545 NLMISC::CVector vector = CVector(0.f, -distance, 0.f);
546 NLMISC::CQuat rot = getOrientation();
547 rot.invert();
548 NLMISC::CMatrix mat;
549 mat.rotate(rot);
550 //if (m_Stage % 2) mat.translate(CVector(m_DevicePtr->HMDInfo.InterpupillaryDistance * -0.5f, 0.f, 0.f));
551 //else mat.translate(CVector(m_DevicePtr->HMDInfo.InterpupillaryDistance * 0.5f, 0.f, 0.f));
552 mat.translate(vector);
553 CVector proj = CStereoOVR::getCurrentFrustum(cid).project(mat.getPos());
555 NLMISC::CVector ipd;
556 if (m_Stage % 2) ipd = CVector(m_DevicePtr->HMDInfo.InterpupillaryDistance * -0.5f, 0.f, 0.f);
557 else ipd = CVector(m_DevicePtr->HMDInfo.InterpupillaryDistance * 0.5f, 0.f, 0.f);
558 CVector projipd = CStereoOVR::getCurrentFrustum(cid).project(vector + ipd);
559 CVector projvec = CStereoOVR::getCurrentFrustum(cid).project(vector);
561 x = (proj.x + projipd.x - projvec.x - 0.5f);
562 y = (proj.y + projipd.y - projvec.y - 0.5f);
564 #elif 1
566 // Alternative method
567 // todo: take into account m_EyePosition
569 NLMISC::CVector vec = CVector(0.f, -distance, 0.f);
570 NLMISC::CVector ipd;
571 if (m_Stage % 2) ipd = CVector((m_DevicePtr->InterpupillaryDistance * m_Scale) * -0.5f, 0.f, 0.f);
572 else ipd = CVector((m_DevicePtr->InterpupillaryDistance * m_Scale) * 0.5f, 0.f, 0.f);
575 NLMISC::CQuat rot = getOrientation();
576 NLMISC::CQuat modrot = NLMISC::CQuat(CVector(0.f, 1.f, 0.f), NLMISC::Pi);
577 rot = rot * modrot;
578 float p = NLMISC::Pi + atan2f(2.0f * ((rot.x * rot.y) + (rot.z * rot.w)), 1.0f - 2.0f * ((rot.y * rot.y) + (rot.w * rot.w)));
579 if (p > NLMISC::Pi) p -= NLMISC::Pi * 2.0f;
580 float t = -atan2f(2.0f * ((rot.x * rot.w) + (rot.y * rot.z)), 1.0f - 2.0f * ((rot.z * rot.z) + (rot.w * rot.w)));// // asinf(2.0f * ((rot.x * rot.z) - (rot.w * rot.y)));
582 CVector rotshift = CVector(p, 0.f, t) * -distance;
584 CVector proj = CStereoLibVR::getCurrentFrustum(cid).project(vec + ipd + rotshift);
586 x = (proj.x - 0.5f);
587 y = (proj.y - 0.5f);
589 #endif
592 void CStereoLibVR::setEyePosition(const NLMISC::CVector &v)
594 m_EyePosition = v;
597 const NLMISC::CVector &CStereoLibVR::getEyePosition() const
599 return m_EyePosition;
602 void CStereoLibVR::setScale(float s)
604 m_EyePosition = m_EyePosition * (s / m_Scale);
605 m_Scale = s;
608 void CStereoLibVR::listDevices(std::vector<CStereoDeviceInfo> &devicesOut)
610 // For now, LibVR doesn't support multiple devices
611 struct hmd *hmd = hmd_open_first(0);
612 if (hmd)
614 CStereoDeviceInfo deviceInfoOut;
615 CStereoLibVRDeviceHandle *handle = new CStereoLibVRDeviceHandle();
616 deviceInfoOut.Factory = static_cast<IStereoDeviceFactory *>(handle);
617 deviceInfoOut.Class = CStereoDeviceInfo::StereoHMD;
618 deviceInfoOut.Library = CStereoDeviceInfo::LibVR;
619 deviceInfoOut.AllowAuto = true;
620 //TODO: manufacturer, produc name
621 //TODO: serial
622 devicesOut.push_back(deviceInfoOut);
623 hmd_close(hmd);
627 bool CStereoLibVR::isLibraryInUse()
629 nlassert(s_DeviceCounter >= 0);
630 return s_DeviceCounter > 0;
633 void CStereoLibVR::releaseLibrary()
635 nlassert(s_DeviceCounter == 0);
638 bool CStereoLibVR::isDeviceCreated()
640 return m_DevicePtr->HMDDevice != NULL;
643 } /* namespace NL3D */
645 #endif /* HAVE_LIBVR */
647 /* end of file */