1 #include "engine.h"
2 
3 #ifdef HAS_OVR
4 #define __PLACEMENT_NEW_INLINE
5 #include "OVR.h"
6 #endif
7 
8 namespace ovr
9 {
10     float fitx = -1.0f, fity = 0.0f, viewoffset = 0.0f, distortoffset = 0.0f, distortscale = 1.0f, fov = 0.0f;
11     float yaw = 0.0f, pitch = 0.0f, roll = 0.0f;
12 
13     GLuint lensfbo[2] = { 0, 0 }, lenstex[2] = { 0, 0 };
14     int lensw = -1, lensh = -1;
15 
16     VARFN(ovr, enabled, 0, 0, 1,
17     {
18         cleanup();
19         cleanupgbuffer();
20         if(enabled && !enable()) enabled = 0;
21         if(!enabled) disable();
22     });
23 
24     VARP(ovrautofov, 0, 0, 1);
25     FVAR(ovrhuddist, 0.01f, 1, 100);
26     FVAR(ovrhudfov, 10, 75, 150);
27 
28     VARFP(ovrscale, 0, 0, 1, { cleanup(); cleanupgbuffer(); });
29     VARFP(ovralignx, -1, -1, 1, { cleanup(); cleanupgbuffer(); });
30     VARFP(ovraligny, -1, -1, 1, { cleanup(); cleanupgbuffer(); });
31 
32     FVAR(ovrviewoffsetscale, 0, 8, 1e3f);
33     VAR(ovrdistort, 0, 1, 1);
34 
35 #ifndef HAS_OVR
init()36     void init() {}
destroy()37     void destroy() {}
setup()38     void setup() {}
cleanup()39     void cleanup() {}
enable()40     bool enable() { return false; }
disable()41     void disable() {}
reset()42     void reset() {}
update()43     void update() {}
warp()44     void warp() {}
ortho(matrix4 & m,float dist,float fov)45     void ortho(matrix4 &m, float dist, float fov) {}
46 #else
47     using namespace OVR;
48 
49     DeviceManager *manager = NULL;
50     HMDDevice *hmd = NULL;
51     SensorDevice *sensor = NULL;
52     SensorFusion *fusion = NULL;
53     HMDInfo hmdinfo;
54 
55     bool inited = false;
56 
init()57     void init()
58     {
59         if(inited) return;
60         System::Init();
61         inited = true;
62     }
63 
distortfn(float r)64     static inline float distortfn(float r)
65     {
66         float r2 = r*r;
67         return r*(hmdinfo.DistortionK[0] +
68                  r2*(hmdinfo.DistortionK[1] +
69                    r2*(hmdinfo.DistortionK[2] +
70                      r2*hmdinfo.DistortionK[3])));
71     }
72 
ortho(matrix4 & m,float dist,float fov)73     void ortho(matrix4 &m, float dist, float fov)
74     {
75         if(dist <= 0) dist = ovrhuddist;
76         if(fov <= 0) fov = ovrhudfov;
77 
78         float size = hmdinfo.VResolution/hmdinfo.VScreenSize * 2.0f*tan(fov*RAD*0.5f)*hmdinfo.EyeToScreenDistance/distortscale;
79         m.scalexy(size/hudw, size/hudh);
80 
81         float shift = (hmdinfo.EyeToScreenDistance/dist) * hmdinfo.InterpupillaryDistance/hmdinfo.HScreenSize,
82               offset = hmdinfo.HResolution * (0.5f*distortoffset + shift/distortscale);
83         m.jitter((viewidx ? -1 : 1)*offset/hudw, 0);
84     }
85 
getorient()86     void getorient()
87     {
88         if(!sensor) return;
89         Quatf orient = fusion->GetOrientation();
90         vec angles = quat(orient.z, orient.y, orient.x, -orient.w).calcangles().div(RAD);
91         yaw = angles.x;
92         pitch = -angles.y;
93         roll = angles.z;
94     }
95 
update()96     void update()
97     {
98         if(!enabled) return;
99         float lastyaw = yaw, lastpitch = pitch;
100         getorient();
101         modifyorient(yaw - lastyaw, pitch - lastpitch);
102     }
103 
recalc()104     void recalc()
105     {
106         if(hmdinfo.HScreenSize > 0.140f) { fitx = -1.0f; fity = 0.0f; }
107         else { fitx = 0.0f; fity = 1.0f; }
108 
109         viewoffset = 0.5f*hmdinfo.InterpupillaryDistance * ovrviewoffsetscale;
110 
111         distortoffset = 1.0f - 2.0f*hmdinfo.LensSeparationDistance/hmdinfo.HScreenSize;
112 
113         if(ovrdistort && (fitx || fity))
114         {
115             float dx = fitx - distortoffset, dy = (fity * hudh) / hudw, r = sqrtf(dx*dx + dy*dy);
116             distortscale = distortfn(r) / r;
117         }
118         else distortscale = 1.0f;
119 
120         if(ovrautofov)
121         {
122             float aspect = forceaspect ? forceaspect : hudw/float(hudh);
123             fov = 2*atan(0.5f*hmdinfo.VScreenSize*distortscale*aspect/hmdinfo.EyeToScreenDistance)/RAD;
124         }
125         else fov = 0;
126     }
127 
setup()128     void setup()
129     {
130         if(!enabled) return;
131         if(ovrscale)
132         {
133             hudw = hudw/2;
134             renderw = renderw/2;
135         }
136         else
137         {
138             hudw = renderw = hmdinfo.HResolution/2;
139             hudh = renderh = hmdinfo.VResolution;
140         }
141         recalc();
142         if(hudw == lensw && hudh == lensh) return;
143         lensw = hudw;
144         lensh = hudh;
145         loopi(2)
146         {
147             if(!lensfbo[i]) glGenFramebuffers_(1, &lensfbo[i]);
148             if(!lenstex[i]) glGenTextures(1, &lenstex[i]);
149             glBindFramebuffer_(GL_FRAMEBUFFER, lensfbo[i]);
150             createtexture(lenstex[i], lensw, lensh, NULL, 3, 1, GL_RGB, GL_TEXTURE_RECTANGLE);
151             glTexParameteri(GL_TEXTURE_RECTANGLE, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
152             glTexParameteri(GL_TEXTURE_RECTANGLE, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
153             GLfloat border[4] = { 0, 0, 0, 1 };
154             glTexParameterfv(GL_TEXTURE_RECTANGLE, GL_TEXTURE_BORDER_COLOR, border);
155             glFramebufferTexture2D_(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_RECTANGLE, lenstex[i], 0);
156             if(glCheckFramebufferStatus_(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
157                 fatal("failed allocating OVR buffer!");
158         }
159         glBindFramebuffer_(GL_FRAMEBUFFER, 0);
160         useshaderbyname("ovrwarp");
161         loopi(3)
162         {
163             glBindFramebuffer_(GL_FRAMEBUFFER, 0);
164             glViewport(0, 0, screenw, screenh);
165             glClearColor(0, 0, 0, 0);
166             glClear(GL_COLOR_BUFFER_BIT);
167             SDL_GL_SwapWindow(screen);
168         }
169     }
170 
cleanup()171     void cleanup()
172     {
173         if(lensfbo[0])
174         {
175             glBindFramebuffer_(GL_FRAMEBUFFER, 0);
176             glViewport(0, 0, screenw, screenh);
177         }
178         loopi(2)
179         {
180             if(lensfbo[i]) { glDeleteFramebuffers_(1, &lensfbo[i]); lensfbo[i] = 0; }
181             if(lenstex[i]) { glDeleteTextures(1, &lenstex[i]); lenstex[i] = 0; }
182         }
183         lensw = lensh = -1;
184     }
185 
warp()186     void warp()
187     {
188         int x = hudx, y = 0, w = hudw, h = hudh;
189         if(ovrscale)
190         {
191             x = viewidx*(screenw/2);
192             w = screenw/2;
193             h = screenh;
194         }
195         else
196         {
197             if(ovralignx > 0) x += max(screenw - 2*hudw, 0);
198             else if(!ovralignx) x += max(screenw - 2*hudw, 0)/2;
199             if(ovraligny < 0) y += max(screenh - hudh, 0);
200             else if(!ovraligny) y += max(screenh - hudh, 0)/2;
201         }
202         if(x >= screenw || y >= screenh) return;
203         glBindFramebuffer_(GL_FRAMEBUFFER, 0);
204         glViewport(x, y, min(w, screenw - x), min(h, screenh - y));
205         glBindTexture(GL_TEXTURE_RECTANGLE, lenstex[viewidx]);
206         SETSHADER(ovrwarp);
207         LOCALPARAMF(lenscenter, (1 + (viewidx ? -1 : 1)*distortoffset)*0.5f*hudw, 0.5f*hudh);
208         LOCALPARAMF(lensscale, 2.0f/hudw, 2.0f/(hudh*aspect), 0.5f*hudw/distortscale, 0.5f*hudh*aspect/distortscale);
209         LOCALPARAMF(distortk, hmdinfo.DistortionK[0], hmdinfo.DistortionK[1], hmdinfo.DistortionK[2], hmdinfo.DistortionK[3]);
210         screenquad(min(w, screenw - x)/float(w)*hudw, min(h, screenh - y)/float(h)*hudh);
211     }
212 
disable()213     void disable()
214     {
215         if(sensor) { sensor->Release(); sensor = NULL; }
216         if(fusion) { delete fusion; fusion = NULL; }
217         if(hmd) { hmd->Release(); hmd = NULL; }
218         if(manager) { manager->Release(); manager = NULL; }
219     }
220 
reset()221     void reset()
222     {
223         if(sensor)
224         {
225             fusion->Reset();
226             getorient();
227         }
228     }
229 
enable()230     bool enable()
231     {
232         init();
233         if(!manager) manager = DeviceManager::Create();
234         if(!hmd) hmd = manager->EnumerateDevices<HMDDevice>().CreateDevice();
235         if(hmd)
236         {
237             if(hmd->GetDeviceInfo(&hmdinfo))
238             {
239                 if(!sensor) sensor = hmd->GetSensor();
240                 if(sensor)
241                 {
242                     if(fusion) fusion->AttachToSensor(sensor);
243                     else fusion = new SensorFusion(sensor);
244                     getorient();
245                 }
246                 conoutf("detected %s (%s), %ux%u, %.1fcm x %.1fcm, %s", hmdinfo.ProductName, hmdinfo.Manufacturer, hmdinfo.HResolution, hmdinfo.VResolution, hmdinfo.HScreenSize*100.0f, hmdinfo.VScreenSize*100.0f, sensor ? "using sensor" : "no sensor");
247                 if(screen) SDL_SetWindowPosition(screen, 0, 0);
248             }
249             else { hmd->Release(); hmd = NULL; }
250         }
251         return hmd!=NULL;
252     }
253 
destroy()254     void destroy()
255     {
256         disable();
257 
258         if(inited) { System::Destroy(); inited = false; }
259     }
260 #endif
261 }
262 
263