From b04d278a27618fb2badb4db98c7da0b69456c77e Mon Sep 17 00:00:00 2001 From: kaetemi Date: Fri, 28 Jun 2013 23:19:32 +0200 Subject: [PATCH] Create interface classes for stereo displays and head mounted displays, see #43 --- code/nel/include/nel/3d/stereo_display.h | 139 ++++++++++++++++++ code/nel/include/nel/3d/stereo_hmd.h | 69 +++++++++ code/nel/include/nel/3d/stereo_ovr.h | 29 +--- code/nel/src/3d/stereo_display.cpp | 98 ++++++++++++ code/nel/src/3d/stereo_hmd.cpp | 55 +++++++ code/nel/src/3d/stereo_ovr.cpp | 47 +++--- code/snowballs2/client/src/camera.cpp | 44 +++--- code/snowballs2/client/src/snowballs_client.h | 6 +- 8 files changed, 423 insertions(+), 64 deletions(-) create mode 100644 code/nel/include/nel/3d/stereo_display.h create mode 100644 code/nel/include/nel/3d/stereo_hmd.h create mode 100644 code/nel/src/3d/stereo_display.cpp create mode 100644 code/nel/src/3d/stereo_hmd.cpp diff --git a/code/nel/include/nel/3d/stereo_display.h b/code/nel/include/nel/3d/stereo_display.h new file mode 100644 index 000000000..b2547bef9 --- /dev/null +++ b/code/nel/include/nel/3d/stereo_display.h @@ -0,0 +1,139 @@ +/** + * \file stereo_display.h + * \brief IStereoDisplay + * \date 2013-06-27 16:29GMT + * \author Jan Boon (Kaetemi) + * IStereoDisplay + */ + +/* + * Copyright (C) 2013 by authors + * + * This file is part of NL3D. + * NL3D is free software: you can redistribute it and/or modify it + * under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * NL3D is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General + * Public License for more details. + * + * You should have received a copy of the GNU Affero General Public + * License along with NL3D. If not, see + * . + */ + +#ifndef NL3D_STEREO_DISPLAY_H +#define NL3D_STEREO_DISPLAY_H +#include + +// STL includes + +// NeL includes +#include + +// Project includes + +namespace NL3D { + +class UCamera; +class CViewport; +class CFrustum; +class IStereoDisplay; + +class IStereoDeviceFactory : public NLMISC::CRefCount +{ +public: + IStereoDeviceFactory() { } + virtual ~IStereoDeviceFactory() { } + virtual IStereoDisplay *createDevice() const = 0; +}; + +struct CStereoDeviceInfo +{ +public: + enum TStereoDeviceClass + { + StereoDisplay, + StereoHMD, + }; + + enum TStereoDeviceLibrary + { + NeL3D, + OVR, + LibVR, + OpenHMD, + }; + + NLMISC::CSmartPtr Factory; + + TStereoDeviceLibrary Library; + TStereoDeviceClass Class; + std::string Manufacturer; + std::string ProductName; + std::string Serial; // A unique device identifier +}; + +/** + * \brief IStereoDisplay + * \date 2013-06-27 16:29GMT + * \author Jan Boon (Kaetemi) + * IStereoDisplay + */ +class IStereoDisplay +{ +public: + IStereoDisplay(); + virtual ~IStereoDisplay(); + + /// Gets the required screen resolution for this device + virtual void getScreenResolution(uint &width, uint &height) = 0; + /// Set latest camera position etcetera + virtual void updateCamera(uint cid, const NL3D::UCamera *camera) = 0; + /// Get the frustum to use for clipping + virtual void getClippingFrustum(uint cid, NL3D::UCamera *camera) const = 0; + + /// Is there a next pass + virtual bool nextPass() = 0; + /// Gets the current viewport + virtual const NL3D::CViewport &getCurrentViewport() const = 0; + /// Gets the current camera frustum + virtual const NL3D::CFrustum &getCurrentFrustum(uint cid) const = 0; + /// Gets the current camera frustum + virtual void getCurrentFrustum(uint cid, NL3D::UCamera *camera) const = 0; + /// Gets the current camera matrix + virtual void getCurrentMatrix(uint cid, NL3D::UCamera *camera) const = 0; + + /// At the start of a new render target + virtual bool beginClear() = 0; + // virtual void *getRenderTarget() const; + virtual void endClear() = 0; + + /// The 3D scene + virtual bool beginScene() = 0; + virtual void endScene() = 0; + + /// Interface within the 3D scene + virtual bool beginInterface3D() = 0; + virtual void endInterface3D() = 0; + + /// 2D Interface + virtual bool beginInterface2D() = 0; + virtual void endInterface2D() = 0; + + static const char *getLibraryName(CStereoDeviceInfo::TStereoDeviceLibrary library); + static void listDevices(std::vector &devicesOut); + static IStereoDisplay *createDevice(const CStereoDeviceInfo &deviceInfo); + static void releaseUnusedLibraries(); + static void releaseAllLibraries(); + +}; /* class IStereoDisplay */ + +} /* namespace NL3D */ + +#endif /* #ifndef NL3D_STEREO_DISPLAY_H */ + +/* end of file */ diff --git a/code/nel/include/nel/3d/stereo_hmd.h b/code/nel/include/nel/3d/stereo_hmd.h new file mode 100644 index 000000000..bbb80368e --- /dev/null +++ b/code/nel/include/nel/3d/stereo_hmd.h @@ -0,0 +1,69 @@ +/** + * \file stereo_hmd.h + * \brief IStereoHMD + * \date 2013-06-27 16:30GMT + * \author Jan Boon (Kaetemi) + * IStereoHMD + */ + +/* + * Copyright (C) 2013 by authors + * + * This file is part of NL3D. + * NL3D is free software: you can redistribute it and/or modify it + * under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * NL3D is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General + * Public License for more details. + * + * You should have received a copy of the GNU Affero General Public + * License along with NL3D. If not, see + * . + */ + +#ifndef NL3D_STEREO_HMD_H +#define NL3D_STEREO_HMD_H +#include + +// STL includes + +// NeL includes + +// Project includes +#include + +namespace NL3D { + +/** + * \brief IStereoHMD + * \date 2013-06-27 16:30GMT + * \author Jan Boon (Kaetemi) + * IStereoHMD + */ +class IStereoHMD : public IStereoDisplay +{ +public: + IStereoHMD(); + virtual ~IStereoHMD(); + + /// Get the HMD orientation + virtual NLMISC::CQuat getOrientation() const = 0; + + /// Set the head model, eye position relative to orientation point + // virtual void setEyePosition(const NLMISC::CVector &v) = 0; + /// Get the head model, eye position relative to orientation point + // virtual const NLMISC::CVector &getEyePosition() const = 0; + /// Get GUI center (1 = width, 1 = height, 0 = center) + virtual void getInterface2DShift(uint cid, float &x, float &y, float distance) const = 0; + +}; /* class IStereoHMD */ + +} /* namespace NL3D */ + +#endif /* #ifndef NL3D_STEREO_HMD_H */ + +/* end of file */ diff --git a/code/nel/include/nel/3d/stereo_ovr.h b/code/nel/include/nel/3d/stereo_ovr.h index ba8d6eac6..e3c8361f8 100644 --- a/code/nel/include/nel/3d/stereo_ovr.h +++ b/code/nel/include/nel/3d/stereo_ovr.h @@ -49,28 +49,16 @@ // NeL includes #include + +// Project includes +#include #include #include -// Project includes - namespace NL3D { -class UCamera; - -struct CStereoDeviceInfo -{ -public: - uint8 Class; - uint8 Identifier; - NLMISC::CSmartPtr Factory; - - std::string Library; - std::string Manufacturer; - std::string ProductName; -}; - class CStereoOVRDevicePtr; +class CStereoOVRDeviceHandle; #define NL_STEREO_MAX_USER_CAMERAS 8 @@ -80,10 +68,10 @@ class CStereoOVRDevicePtr; * \author Jan Boon (Kaetemi) * CStereoOVR */ -class CStereoOVR +class CStereoOVR : public IStereoHMD { public: - CStereoOVR(const CStereoDeviceInfo &deviceInfo); + CStereoOVR(const CStereoOVRDeviceHandle *handle); virtual ~CStereoOVR(); @@ -126,18 +114,17 @@ public: /// Get the HMD orientation virtual NLMISC::CQuat getOrientation() const; /// Get GUI center (1 = width, 1 = height, 0 = center) - virtual void getInterface2DShift(uint cid, float &x, float &y, float distance); + virtual void getInterface2DShift(uint cid, float &x, float &y, float distance) const; static void listDevices(std::vector &devicesOut); - static CStereoOVR *createDevice(const CStereoDeviceInfo &deviceInfo); static bool isLibraryInUse(); static void releaseLibrary(); /// Calculates internal camera information based on the reference camera void initCamera(uint cid, const NL3D::UCamera *camera); - + /// Checks if the device used by this class was actually created bool isDeviceCreated(); private: diff --git a/code/nel/src/3d/stereo_display.cpp b/code/nel/src/3d/stereo_display.cpp new file mode 100644 index 000000000..09502a256 --- /dev/null +++ b/code/nel/src/3d/stereo_display.cpp @@ -0,0 +1,98 @@ +/** + * \file stereo_display.cpp + * \brief IStereoDisplay + * \date 2013-06-27 16:29GMT + * \author Jan Boon (Kaetemi) + * IStereoDisplay + */ + +/* + * Copyright (C) 2013 by authors + * + * This file is part of NL3D. + * NL3D is free software: you can redistribute it and/or modify it + * under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * NL3D is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General + * Public License for more details. + * + * You should have received a copy of the GNU Affero General Public + * License along with NL3D. If not, see + * . + */ + +#include +#include + +// STL includes + +// NeL includes +// #include + +// Project includes +#include + +using namespace std; +// using namespace NLMISC; + +namespace NL3D { + +IStereoDisplay::IStereoDisplay() +{ + +} + +IStereoDisplay::~IStereoDisplay() +{ + +} + +const char *IStereoDisplay::getLibraryName(CStereoDeviceInfo::TStereoDeviceLibrary library) +{ + static const char *nel3dName = "NeL 3D"; + static const char *ovrName = "Oculus SDK"; + static const char *libvrName = "LibVR"; + static const char *openhmdName = "OpenHMD"; + switch (library) + { + case CStereoDeviceInfo::NeL3D: + return nel3dName; + case CStereoDeviceInfo::OVR: + return ovrName; + case CStereoDeviceInfo::LibVR: + return libvrName; + case CStereoDeviceInfo::OpenHMD: + return openhmdName; + } + nlerror("Invalid device library specified"); + return ""; +} + +void IStereoDisplay::listDevices(std::vector &devicesOut) +{ + CStereoOVR::listDevices(devicesOut); +} + +IStereoDisplay *IStereoDisplay::createDevice(const CStereoDeviceInfo &deviceInfo) +{ + return deviceInfo.Factory->createDevice(); +} + +void IStereoDisplay::releaseUnusedLibraries() +{ + if (!CStereoOVR::isLibraryInUse()) + CStereoOVR::releaseLibrary(); +} + +void IStereoDisplay::releaseAllLibraries() +{ + CStereoOVR::releaseLibrary(); +} + +} /* namespace NL3D */ + +/* end of file */ diff --git a/code/nel/src/3d/stereo_hmd.cpp b/code/nel/src/3d/stereo_hmd.cpp new file mode 100644 index 000000000..d28017482 --- /dev/null +++ b/code/nel/src/3d/stereo_hmd.cpp @@ -0,0 +1,55 @@ +/** + * \file stereo_hmd.cpp + * \brief IStereoHMD + * \date 2013-06-27 16:30GMT + * \author Jan Boon (Kaetemi) + * IStereoHMD + */ + +/* + * Copyright (C) 2013 by authors + * + * This file is part of NL3D. + * NL3D is free software: you can redistribute it and/or modify it + * under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * NL3D is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General + * Public License for more details. + * + * You should have received a copy of the GNU Affero General Public + * License along with NL3D. If not, see + * . + */ + +#include +#include + +// STL includes + +// NeL includes +// #include + +// Project includes + +using namespace std; +// using namespace NLMISC; + +namespace NL3D { + +IStereoHMD::IStereoHMD() +{ + +} + +IStereoHMD::~IStereoHMD() +{ + +} + +} /* namespace NL3D */ + +/* end of file */ diff --git a/code/nel/src/3d/stereo_ovr.cpp b/code/nel/src/3d/stereo_ovr.cpp index f6c063de4..f4cb61e1a 100644 --- a/code/nel/src/3d/stereo_ovr.cpp +++ b/code/nel/src/3d/stereo_ovr.cpp @@ -45,6 +45,7 @@ #include // STL includes +#include // External includes #include @@ -127,16 +128,24 @@ public: CStereoOVRSystem s_StereoOVRSystem; -class CStereoOVRDeviceHandle : public NLMISC::CRefCount -{ -public: - OVR::DeviceEnumerator DeviceHandle; -}; - sint s_DeviceCounter = 0; } +class CStereoOVRDeviceHandle : public IStereoDeviceFactory +{ +public: + OVR::DeviceEnumerator DeviceHandle; + IStereoDisplay *createDevice() const + { + CStereoOVR *stereo = new CStereoOVR(this); + if (stereo->isDeviceCreated()) + return stereo; + delete stereo; + return NULL; + } +}; + class CStereoOVRDevicePtr { public: @@ -146,12 +155,11 @@ public: OVR::HMDInfo HMDInfo; }; -CStereoOVR::CStereoOVR(const CStereoDeviceInfo &deviceInfo) : m_Stage(0), m_OrientationCached(false) +CStereoOVR::CStereoOVR(const CStereoOVRDeviceHandle *handle) : m_Stage(0), m_OrientationCached(false) { ++s_DeviceCounter; m_DevicePtr = new CStereoOVRDevicePtr(); - CStereoOVRDeviceHandle *handle = static_cast(deviceInfo.Factory.getPtr()); OVR::DeviceEnumerator dh = handle->DeviceHandle; m_DevicePtr->HMDDevice = dh.CreateDevice(); @@ -406,7 +414,7 @@ NLMISC::CQuat CStereoOVR::getOrientation() const } /// Get GUI shift -void CStereoOVR::getInterface2DShift(uint cid, float &x, float &y, float distance) +void CStereoOVR::getInterface2DShift(uint cid, float &x, float &y, float distance) const { #if 0 @@ -460,7 +468,7 @@ void CStereoOVR::listDevices(std::vector &devicesOut) { s_StereoOVRSystem.Init(); OVR::DeviceEnumerator devices = s_DeviceManager->EnumerateDevices(); - uint8 id = 1; + uint id = 1; do { CStereoDeviceInfo deviceInfoOut; @@ -469,13 +477,15 @@ void CStereoOVR::listDevices(std::vector &devicesOut) { devices.GetDeviceInfo(&deviceInfo); CStereoOVRDeviceHandle *handle = new CStereoOVRDeviceHandle(); - deviceInfoOut.Factory = static_cast(handle); + deviceInfoOut.Factory = static_cast(handle); handle->DeviceHandle = devices; - deviceInfoOut.Class = 1; // OVR::HMDDevice - deviceInfoOut.Library = "Oculus SDK"; - deviceInfoOut.Identifier = id; + deviceInfoOut.Class = CStereoDeviceInfo::StereoHMD; // 1; // OVR::HMDDevice + deviceInfoOut.Library = CStereoDeviceInfo::OVR; // "Oculus SDK"; deviceInfoOut.Manufacturer = deviceInfo.Manufacturer; deviceInfoOut.ProductName = deviceInfo.ProductName; + stringstream ser; + ser << id; + deviceInfoOut.Serial = ser.str(); // can't get the real serial from the sdk... devicesOut.push_back(deviceInfoOut); ++id; } @@ -483,15 +493,6 @@ void CStereoOVR::listDevices(std::vector &devicesOut) } while (devices.Next()); } -CStereoOVR *CStereoOVR::createDevice(const CStereoDeviceInfo &deviceInfo) -{ - CStereoOVR *stereo = new CStereoOVR(deviceInfo); - if (stereo->isDeviceCreated()) - return stereo; - delete stereo; - return NULL; -} - bool CStereoOVR::isLibraryInUse() { nlassert(s_DeviceCounter >= 0); diff --git a/code/snowballs2/client/src/camera.cpp b/code/snowballs2/client/src/camera.cpp index ef65a7a9f..f4f5ea2b4 100644 --- a/code/snowballs2/client/src/camera.cpp +++ b/code/snowballs2/client/src/camera.cpp @@ -34,7 +34,7 @@ #include #include -#include +#include #include "snowballs_client.h" #include "entities.h" @@ -70,7 +70,8 @@ static UInstance Sky = NULL; static UCloudScape *Clouds = NULL; -CStereoOVR *StereoHMD = NULL; +IStereoDisplay *StereoDisplay = NULL; +IStereoHMD *StereoHMD = NULL; // // Functions @@ -81,12 +82,12 @@ void initCamera() if (ConfigFile->getVar("HMDEnable").asBool()) { std::vector devices; - CStereoOVR::listDevices(devices); + IStereoDisplay::listDevices(devices); for (std::vector::iterator it(devices.begin()), end(devices.end()); it != end; ++it) { std::stringstream name; - name << std::string("[") << (uint32)it->Identifier << "] [" << it->Library << " - " << it->Manufacturer << " - " << it->ProductName << "]"; - nlinfo("Stereo Device: %s", name.str().c_str()); + name << std::string("[") << it->Serial << "] [" << IStereoDisplay::getLibraryName(it->Library) << " - " << it->Manufacturer << " - " << it->ProductName << "]"; + nlinfo("Stereo Display: %s", name.str().c_str()); } CStereoDeviceInfo *deviceInfo = NULL; std::string hmdDeviceCfg = ConfigFile->getVar("HMDDevice").asString(); @@ -97,22 +98,28 @@ void initCamera() } else { - uint8 hmdDeviceId = (ConfigFile->getVar("HMDDeviceId").asInt() & 0xFF); + std::string hmdDeviceId = ConfigFile->getVar("HMDDeviceId").asString(); for (std::vector::iterator it(devices.begin()), end(devices.end()); it != end; ++it) { std::stringstream name; - name << it->Library << " - " << it->Manufacturer << " - " << it->ProductName; + name << IStereoDisplay::getLibraryName(it->Library) << " - " << it->Manufacturer << " - " << it->ProductName; if (name.str() == hmdDeviceCfg) deviceInfo = &(*it); - if (hmdDeviceId == it->Identifier) + if (hmdDeviceId == it->Serial) break; } } if (deviceInfo) { - nlinfo("Create HMD device!"); - StereoHMD = CStereoOVR::createDevice(*deviceInfo); + nlinfo("Create VR stereo display device"); + StereoDisplay = IStereoDisplay::createDevice(*deviceInfo); + if (deviceInfo->Class == CStereoDeviceInfo::StereoHMD) + { + nlinfo("Stereo display device is a HMD"); + StereoHMD = static_cast(StereoDisplay); + } } + IStereoDisplay::releaseUnusedLibraries(); } // Set up directly the camera @@ -129,11 +136,6 @@ void initCamera() CamCollisionEntity = VisualCollisionManager->createEntity(); CamCollisionEntity->setCeilMode(true); - if (StereoHMD) - { - StereoHMD->initCamera(0, &Camera); - } - // Create the snowing particle system Snow = Scene->createInstance("snow.ps"); // And setup it @@ -164,9 +166,15 @@ void releaseCamera() Scene->deleteInstance(Snow); VisualCollisionManager->deleteEntity(CamCollisionEntity); - delete StereoHMD; - StereoHMD = NULL; - CStereoOVR::releaseLibrary(); + if (StereoHMD) + { + delete StereoHMD; + StereoHMD = NULL; + StereoDisplay = NULL; + } + delete StereoDisplay; + StereoDisplay = NULL; + IStereoDisplay::releaseAllLibraries(); } void updateCamera() diff --git a/code/snowballs2/client/src/snowballs_client.h b/code/snowballs2/client/src/snowballs_client.h index bc955d317..d21f925f7 100644 --- a/code/snowballs2/client/src/snowballs_client.h +++ b/code/snowballs2/client/src/snowballs_client.h @@ -42,7 +42,8 @@ namespace NL3D { class UScene; class UTextContext; class ULandscape; - class CStereoOVR; + class IStereoDisplay; + class IStereoHMD; } namespace SBCLIENT { @@ -59,7 +60,8 @@ public: }; extern NL3D::UDriver *Driver; -extern NL3D::CStereoOVR *StereoHMD; +extern NL3D::IStereoDisplay *StereoDisplay; +extern NL3D::IStereoHMD *StereoHMD; extern NL3D::UScene *Scene; extern NL3D::UTextContext *TextContext; extern NLMISC::CConfigFile *ConfigFile;