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