| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459 |
- /******************************************************************************/
- #include "stdafx.h"
- #define SUPPORT_OCULUS (WINDOWS_OLD && DX11)
- #if SUPPORT_OCULUS
- #include "../../../ThirdPartyLibs/begin.h"
- //#include "../../../ThirdPartyLibs/Oculus/LibOVR/Include/OVR.h"
- #include "../../../ThirdPartyLibs/Oculus/LibOVR/Include/OVR_CAPI.h"
- #if DX11
- #include "../../../ThirdPartyLibs/Oculus/LibOVR/Include/OVR_CAPI_D3D.h"
- #elif GL
- #include "../../../ThirdPartyLibs/Oculus/LibOVR/Include/OVR_CAPI_GL.h"
- #endif
- #include "../../../ThirdPartyLibs/end.h"
- #endif
- /******************************************************************************/
- namespace EE{
- /******************************************************************************/
- static struct OculusRiftApi : VirtualRealityApi
- {
- virtual Bool init()override;
- virtual void shut()override;
- virtual Bool active ()C override;
- virtual Matrix matrixCur ()C override;
- virtual void recenter () override;
- virtual void changedGuiDepth() override;
- virtual void changedGuiSize () override;
- virtual void update () override;
- virtual void draw () override;
- virtual void delImages()override;
- virtual Bool createGuiImage ()override;
- virtual Bool createRenderImage ()override;
- virtual ImageRC* getNewRender ()override;
- virtual ImageRC* getNewGui ()override;
- virtual ImageRC* getLastRender()override;
- virtual ImageRC* getLastGui ()override;
- Bool connect();
- void disconnect();
- void setGuiSizeX();
- void setGuiSize ();
- OculusRiftApi();
- #if SUPPORT_OCULUS
- //private:
- Bool _initialized;
- ovrSession _session;
- ovrLayerEyeFov _layer_render;
- ovrLayerQuad _layer_gui;
- #endif
- }OculusRift;
- /******************************************************************************/
- #if SUPPORT_OCULUS
- static struct ovrTexture
- {
- ImageRC image;
- ovrSwapTextureSet *texture_set;
- #if DX11
- ID3D11RenderTargetView *rtv[3];
- ID3D11ShaderResourceView *srv[3];
- #endif
- ~ovrTexture() {del();}
- ovrTexture()
- {
- texture_set=null;
- #if DX11
- REPAO(rtv)=null;
- REPAO(srv)=null;
- #endif
- }
- void del()
- {
- image.zero(); // !! zero without deleting, because members were just copied !!
- #if DX11
- if(D.created())
- {
- REPA(rtv)RELEASE(rtv[i]);
- REPA(srv)RELEASE(srv[i]);
- }else
- {
- REPAO(rtv)=null;
- REPAO(srv)=null;
- }
- #endif
- if(OculusRift._session)ovr_DestroySwapTextureSet(OculusRift._session, texture_set); texture_set=null;
- }
- Bool create(Int w, Int h)
- {
- del();
- // TODO: support gamma correct sRGB rendering
- image._size=image._hw_size.set(w, h, 1);
- image._type=image._hw_type=IMAGE_R8G8B8A8;
- image._mode=IMAGE_RT;
- image._mms=1;
- image._samples=1;
- image._byte_pp=ImageTI[image.type()].byte_pp;
- image. setPartial();
- #if DX11
- D3D11_TEXTURE2D_DESC desc;
- desc.Width =image.w();
- desc.Height =image.h();
- desc.MipLevels =1;
- desc.Format =DXGI_FORMAT_R8G8B8A8_UNORM_SRGB;
- desc.Usage =D3D11_USAGE_DEFAULT;
- desc.BindFlags =D3D11_BIND_RENDER_TARGET|D3D11_BIND_SHADER_RESOURCE;
- desc.MiscFlags =0;
- desc.CPUAccessFlags =0;
- desc.SampleDesc.Count =1;
- desc.SampleDesc.Quality=0;
- desc.ArraySize =1;
- //SyncLockerEx locker(D._lock); lock not needed for DX11 'D3D'
- if(ovr_CreateSwapTextureSetD3D11(OculusRift._session, D3D, &desc, ovrSwapTextureSetD3D11_Typeless, &texture_set)==ovrSuccess)
- {
- if (texture_set->TextureCount>Elms(rtv))Exit("Oculus Rift Swap Chain has too many textures");
- FREP(texture_set->TextureCount)
- {
- ovrD3D11Texture &tex=(ovrD3D11Texture&)texture_set->Textures[i];
- D3D11_RENDER_TARGET_VIEW_DESC rtvd; Zero(rtvd);
- rtvd.Format =DXGI_FORMAT_R8G8B8A8_UNORM;
- rtvd.ViewDimension=D3D11_RTV_DIMENSION_TEXTURE2D;
- if(!OK(D3D->CreateRenderTargetView(tex.D3D11.pTexture, &rtvd, &rtv[i])))goto error;
- D3D11_SHADER_RESOURCE_VIEW_DESC srvd; Zero(srvd);
- srvd.Format =DXGI_FORMAT_R8G8B8A8_UNORM;
- srvd.ViewDimension =D3D11_SRV_DIMENSION_TEXTURE2D;
- srvd.Texture2D.MipLevels=1;
- if(!OK(D3D->CreateShaderResourceView(tex.D3D11.pTexture, &srvd, &srv[i])))goto error;
- }
- return true;
- }
- #endif
- error:
- del(); return false;
- }
- ImageRC* getImage()
- {
- if(texture_set)
- {
- if( ++texture_set->CurrentIndex>=texture_set->TextureCount)texture_set->CurrentIndex=0;
- Int i=texture_set->CurrentIndex;
- image.unlock(); // unlock if it was locked by the user
- #if DX11
- ovrD3D11Texture &tex=(ovrD3D11Texture&)texture_set->Textures[i];
- image._txtr=tex.D3D11.pTexture;
- image._rtv =rtv[i];
- image._srv =srv[i];
- #endif
- return ℑ
- }
- return null;
- }
- }RenderTexture, GuiTexture;
- static void SetPose(Matrix &m, C ovrPosef &pose)
- {
- ASSERT(SIZE(pose.Orientation)==SIZE(Quaternion)); Quaternion q=(Quaternion&)pose.Orientation; CHS(q.z); m.orn()=q;
- ASSERT(SIZE(pose.Position )==SIZE(Vec )); m.pos.set(pose.Position.x, pose.Position.y, -pose.Position.z); // Oculus is right-handed
- }
- static void SetPose(ovrPosef &pose, C Matrix &m)
- {
- ASSERT(SIZE(pose.Orientation)==SIZE(Quaternion)); (Quaternion&)pose.Orientation=Quaternion(m); CHS(pose.Orientation.z);
- ASSERT(SIZE(pose.Position )==SIZE(Vec )); ((Vec&)pose.Position).set(m.pos.x, m.pos.y, -m.pos.z); // Oculus is right-handed
- }
- void OculusRiftApi::disconnect()
- {
- VR.delImages(); // !! need to call 'VR.delImages' and not 'T.delImages' !!
- if(_session)
- {
- ovr_Destroy(_session); _session=null;
- VR.disconnected(); // call 'disconnected' after clearing '_session' so 'VR.active' is false (needed for some things including 'D.setSync')
- }
- }
- Bool OculusRiftApi::connect()
- {
- disconnect();
- ASSERT(SIZE(VR._adapter_id)==SIZE(ovrGraphicsLuid));
- if(ovr_Create(&_session, (ovrGraphicsLuid*)&VR._adapter_id)==ovrSuccess)
- {
- D.clearFade();
- ovrHmdDesc desc=ovr_GetHmdDesc(_session);
- Set(VR._name, desc.ProductName);
- VR._refresh=desc.DisplayRefreshRate;
- VR._res.set(desc.Resolution.w, desc.Resolution.h);
- VR.setFOVTan(desc.DefaultEyeFov[0].LeftTan, desc.DefaultEyeFov[0].RightTan, desc.DefaultEyeFov[0].UpTan, desc.DefaultEyeFov[0].DownTan);
- ovrEyeRenderDesc eye_render_desc[2]; REPAO(eye_render_desc)=ovr_GetRenderDesc(_session, ovrEyeType(i), desc.DefaultEyeFov[i]);
- ASSERT(SIZE(eye_render_desc[0].HmdToEyeViewOffset)==SIZE(Vec));
- VR._eye_dist=Dist((Vec&)eye_render_desc[0].HmdToEyeViewOffset,
- (Vec&)eye_render_desc[1].HmdToEyeViewOffset);
- REP(2)_layer_render.Fov[i]=desc.DefaultEyeFov[i]; // eyes
- return VR.connected(); // call 'connected' after having set '_session' so 'VR.active' is true (needed for some things including 'D.setSync')
- }
- return false;
- }
- #endif
- /******************************************************************************/
- OculusRiftApi::OculusRiftApi()
- {
- #if SUPPORT_OCULUS
- _initialized=false;
- _session=null;
- Zero(_layer_render);
- _layer_render.Header.Type =ovrLayerType_EyeFov;
- _layer_render.Header.Flags=0;
- Zero(_layer_gui);
- _layer_gui.Header.Type =ovrLayerType_Quad;
- _layer_gui.Header.Flags=ovrLayerFlag_HeadLocked;
- Matrix m; m.identity(); SetPose(_layer_gui.QuadPoseCenter, m);
- _layer_gui.QuadPoseCenter.Position.z=-1; // Oculus is right-handed
- _layer_gui.QuadSize.y=1;
- #endif
- }
- /******************************************************************************/
- Bool VirtualReality::OculusRiftInit () {return VR.init(OculusRift);}
- Bool VirtualReality::OculusRiftDetected()C
- {
- #if SUPPORT_OCULUS
- return ovr_Detect(0).IsOculusHMDConnected!=ovrFalse; // according to headers, this can be called before 'ovr_Initialize'
- #else
- return false;
- #endif
- }
- Bool OculusRiftApi::active()C
- {
- #if SUPPORT_OCULUS
- return _session!=null;
- #else
- return false;
- #endif
- }
- /******************************************************************************/
- Bool OculusRiftApi::init()
- {
- #if SUPPORT_OCULUS
- if(!_initialized && ovr_Initialize(null)==ovrSuccess)
- {
- _initialized=true;
- connect();
- }
- return _initialized;
- #endif
- return false;
- }
- void OculusRiftApi::shut()
- {
- #if SUPPORT_OCULUS
- if(_initialized)
- {
- disconnect();
- _initialized=false;
- ovr_Shutdown();
- }
- #endif
- }
- /******************************************************************************/
- Matrix OculusRiftApi::matrixCur()C
- {
- #if SUPPORT_OCULUS
- if(_session)
- {
- ovrTrackingState ts=ovr_GetTrackingState(_session, 0, ovrFalse); // according to headers, "time 0" will get "the most recent sensor reading"
- if(ts.StatusFlags&(ovrStatus_OrientationTracked|ovrStatus_PositionTracked))
- {
- Matrix m; SetPose(m, ts.HeadPose.ThePose);
- return m;
- }
- }
- #endif
- return VR._matrix; // return last known matrix
- }
- /******************************************************************************/
- void OculusRiftApi::setGuiSizeX()
- {
- #if SUPPORT_OCULUS
- _layer_gui.QuadSize.x=_layer_gui.QuadSize.y*GuiTexture.image.aspect();
- #endif
- }
- void OculusRiftApi::setGuiSize()
- {
- #if SUPPORT_OCULUS
- _layer_gui.QuadSize.y=VR._gui_size*-_layer_gui.QuadPoseCenter.Position.z; // Oculus is right-handed
- #endif
- setGuiSizeX();
- }
- void OculusRiftApi::changedGuiDepth()
- {
- #if SUPPORT_OCULUS
- _layer_gui.QuadPoseCenter.Position.z=-VR.guiDepth(); // Oculus is right-handed
- setGuiSize();
- #endif
- }
- void OculusRiftApi::changedGuiSize()
- {
- #if SUPPORT_OCULUS
- setGuiSize();
- #endif
- }
- /******************************************************************************/
- void OculusRiftApi::delImages()
- {
- #if SUPPORT_OCULUS
- RenderTexture.del();
- GuiTexture.del();
- #endif
- }
- Bool OculusRiftApi::createGuiImage()
- {
- #if SUPPORT_OCULUS
- if(GuiTexture.create(VR.guiRes().x, VR.guiRes().y))
- {
- _layer_gui.ColorTexture=GuiTexture.texture_set;
- _layer_gui.Viewport.Pos .x=_layer_gui.Viewport.Pos.y=0;
- _layer_gui.Viewport.Size.w=GuiTexture.image.w();
- _layer_gui.Viewport.Size.h=GuiTexture.image.h();
- setGuiSizeX();
- return true;
- }
- #endif
- return false;
- }
- Bool OculusRiftApi::createRenderImage()
- {
- #if SUPPORT_OCULUS
- ovrHmdDesc desc=ovr_GetHmdDesc(_session);
- ovrSizei size=ovr_GetFovTextureSize(_session, ovrEye_Left, desc.DefaultEyeFov[0], VR.pixelDensity());
- Clamp(size.w*=2, 2, D.maxTexSize()); // *2 also makes sure that both eyes have the same width
- Clamp(size.h , 1, D.maxTexSize());
- if(RenderTexture.create(size.w, size.h))
- {
- _layer_render.ColorTexture[0]=RenderTexture.texture_set; // setting only to 0 means that texture contains data for both eyes
- _layer_render.ColorTexture[1]=null;
- _layer_render.Viewport[0].Pos .x=_layer_render.Viewport[0].Pos .y=_layer_render.Viewport[1].Pos .y=0;
- _layer_render.Viewport[1].Pos .x=_layer_render.Viewport[0].Size.w=_layer_render.Viewport[1].Size.w=RenderTexture.image.w()/2;
- _layer_render.Viewport[0].Size.h=_layer_render.Viewport[1].Size.h=RenderTexture.image.h();
- return true;
- }
- #endif
- return false;
- }
- /******************************************************************************/
- ImageRC* OculusRiftApi::getNewRender()
- {
- #if SUPPORT_OCULUS
- return RenderTexture.getImage();
- #endif
- return null;
- }
- ImageRC* OculusRiftApi::getNewGui()
- {
- #if SUPPORT_OCULUS
- return GuiTexture.getImage();
- #endif
- return null;
- }
- ImageRC* OculusRiftApi::getLastRender()
- {
- #if SUPPORT_OCULUS
- return &RenderTexture.image;
- #endif
- return null;
- }
- ImageRC* OculusRiftApi::getLastGui()
- {
- #if SUPPORT_OCULUS
- return &GuiTexture.image;
- #endif
- return null;
- }
- /******************************************************************************/
- void OculusRiftApi::recenter()
- {
- #if SUPPORT_OCULUS
- if(_session)ovr_RecenterPose(_session);
- #endif
- }
- /******************************************************************************/
- void OculusRiftApi::update()
- {
- #if SUPPORT_OCULUS
- if(_initialized)
- {
- VR._has_render=false;
- if(_session)
- {
- _layer_render.SensorSampleTime=ovr_GetTimeInSeconds(); // needs to be set at the same time when obtaining sensor data
- ovrTrackingState ts=ovr_GetTrackingState(_session, ovr_GetPredictedDisplayTime(_session, 0), ovrTrue);
- if(ts.StatusFlags&ovrStatus_HmdConnected)
- {
- C ovrVector3f &a=ts.RawSensorData.Accelerometer; AccelerometerValue.set(-a.x, -a.y, a.z);
- C ovrVector3f &g=ts.RawSensorData.Gyro ; GyroscopeValue.set( g.x, g.y, -g.z);
- C ovrVector3f &m=ts.RawSensorData.Magnetometer ; MagnetometerValue.set( m.x, m.y, -m.z);
- if(ts.HandStatusFlags[0]&(ovrStatus_OrientationTracked|ovrStatus_PositionTracked))SetPose(VR._left , ts.HandPoses[0].ThePose);
- if(ts.HandStatusFlags[1]&(ovrStatus_OrientationTracked|ovrStatus_PositionTracked))SetPose(VR._right, ts.HandPoses[1].ThePose);
- if(ts.StatusFlags &(ovrStatus_OrientationTracked|ovrStatus_PositionTracked))
- {
- SetPose(VR._matrix, ts.HeadPose.ThePose);
- #if 0 // slower
- ovrVector3f HmdToEyeViewOffset[2]=
- {
- {D.eyeDistance()*-0.5f, 0, 0},
- {D.eyeDistance()* 0.5f, 0, 0},
- };
- ovr_CalcEyePoses(ts.HeadPose.ThePose, HmdToEyeViewOffset, _layer_render.RenderPose);
- #else
- Vec eye_offset=VR._matrix.x*D.eyeDistance(); CHS(eye_offset.z); // need to change z because Oculus is right-handed
- ASSERT(SIZE(ts.HeadPose.ThePose.Position)==SIZE(Vec));
- (Vec&)ts.HeadPose.ThePose.Position-=eye_offset*0.5f; _layer_render.RenderPose[0]=ts.HeadPose.ThePose;
- (Vec&)ts.HeadPose.ThePose.Position+=eye_offset ; _layer_render.RenderPose[1]=ts.HeadPose.ThePose;
- #endif
- }
- }else disconnect(); // lost connection
- }else
- if(VR.OculusRiftDetected()) // try to connect
- {
- connect();
- }
- }
- #endif
- }
- void OculusRiftApi::draw()
- {
- #if SUPPORT_OCULUS
- if(active())
- {
- #if 0 // this made absolutely no difference, TODO: test in the future with a newer SDK
- FlagSet(_layer_render.Header.Flags, ovrLayerFlag_HighQuality, Ms.b(0));
- FlagSet(_layer_gui .Header.Flags, ovrLayerFlag_HighQuality, Ms.b(1));
- #endif
- ovrLayerHeader *layer[2]; Int layers=0;
- if(VR._has_render)layer[layers++]=&_layer_render.Header;
- if(VR. draw_2d )layer[layers++]=&_layer_gui .Header;
- ovr_SubmitFrame(_session, 0, null, layer, layers);
- }
- #endif
- }
- /******************************************************************************/
- }
- /******************************************************************************/
|