rev |
line source |
nuclear@1
|
1 #include <stdio.h>
|
nuclear@12
|
2 #include <GL/glew.h>
|
nuclear@1
|
3 #include "vr.h"
|
nuclear@1
|
4 #include "vr_impl.h"
|
nuclear@15
|
5 #include "vr_sdr.h"
|
nuclear@12
|
6
|
nuclear@19
|
7 #ifndef WIN32
|
nuclear@19
|
8 #include <alloca.h>
|
nuclear@19
|
9 #else
|
nuclear@19
|
10 #include <malloc.h>
|
nuclear@19
|
11 #endif
|
nuclear@19
|
12
|
nuclear@21
|
13 #define USUB 28
|
nuclear@21
|
14 #define VSUB 40
|
nuclear@21
|
15
|
nuclear@21
|
16 /* these are just used for the shaderless precomputed distortion method */
|
nuclear@21
|
17 struct Mesh {
|
nuclear@21
|
18 int prim;
|
nuclear@21
|
19 int num_verts, num_faces;
|
nuclear@21
|
20 unsigned int vbo;
|
nuclear@21
|
21 unsigned int ibo;
|
nuclear@21
|
22 };
|
nuclear@21
|
23 struct Vertex {
|
nuclear@21
|
24 float x, y, z;
|
nuclear@21
|
25 float tx, ty;
|
nuclear@21
|
26 };
|
nuclear@21
|
27
|
nuclear@21
|
28
|
nuclear@18
|
29 static void init_ctx();
|
nuclear@1
|
30 static bool init_ovr();
|
nuclear@12
|
31 static bool init_sdr();
|
nuclear@1
|
32
|
nuclear@21
|
33 static Mesh gen_view_mesh(int usub, int vsub, float aspect, float lens_center_offset,
|
nuclear@21
|
34 float scale, const float *dist_factors, float tex_scale_x, float tex_scale_y);
|
nuclear@21
|
35 static void distort_texcoords(float *tc, float aspect, float lens_center_offset, float scale, const float *dist_factors);
|
nuclear@21
|
36 static float barrel_scale(float rad, const float *k);
|
nuclear@21
|
37
|
nuclear@3
|
38 VRContext vr_ctx;
|
nuclear@12
|
39 static unsigned int sdrprog;
|
nuclear@1
|
40
|
nuclear@21
|
41 static Mesh wrapmesh[2];
|
nuclear@21
|
42 static bool mesh_valid;
|
nuclear@21
|
43
|
nuclear@21
|
44 bool dbg_enable;
|
nuclear@21
|
45
|
nuclear@21
|
46
|
nuclear@1
|
47 extern "C" int vr_init(enum vr_init_mode mode)
|
nuclear@1
|
48 {
|
nuclear@12
|
49 glewInit();
|
nuclear@12
|
50
|
nuclear@18
|
51 init_ctx();
|
nuclear@18
|
52
|
nuclear@1
|
53 if(!init_ovr()) {
|
nuclear@1
|
54 return -1;
|
nuclear@1
|
55 }
|
nuclear@12
|
56
|
nuclear@12
|
57 if(!init_sdr()) {
|
nuclear@12
|
58 return -1;
|
nuclear@12
|
59 }
|
nuclear@12
|
60
|
nuclear@1
|
61 return 0;
|
nuclear@1
|
62 }
|
nuclear@1
|
63
|
nuclear@1
|
64 extern "C" void vr_shutdown(void)
|
nuclear@1
|
65 {
|
nuclear@15
|
66 delete [] vr_ctx.info.display;
|
nuclear@3
|
67 //System::Destroy();
|
nuclear@1
|
68 }
|
nuclear@1
|
69
|
nuclear@18
|
70 static void init_ctx()
|
nuclear@18
|
71 {
|
nuclear@18
|
72 vr_ctx.info.width = 1280;
|
nuclear@18
|
73 vr_ctx.info.height = 800;
|
nuclear@18
|
74 vr_ctx.info.fov = M_PI / 2.0;
|
nuclear@18
|
75 vr_ctx.info.aspect = (float)vr_ctx.info.width / (float)vr_ctx.info.height;
|
nuclear@18
|
76 vr_ctx.info.ipd = 0.035;
|
nuclear@18
|
77 vr_ctx.info.scale = 1.0;
|
nuclear@18
|
78 }
|
nuclear@18
|
79
|
nuclear@1
|
80 static bool init_ovr()
|
nuclear@1
|
81 {
|
nuclear@8
|
82 LogMaskConstants log_level = LogMask_All;
|
nuclear@1
|
83 // initialize Oculus SDK
|
nuclear@5
|
84 const char *logenv = getenv("VR_LOGLEVEL");
|
nuclear@5
|
85 if(logenv) {
|
nuclear@5
|
86 switch(atoi(logenv)) {
|
nuclear@5
|
87 case 0:
|
nuclear@5
|
88 log_level = LogMask_None;
|
nuclear@5
|
89 break;
|
nuclear@5
|
90 case 1:
|
nuclear@5
|
91 log_level = LogMask_Regular;
|
nuclear@5
|
92 break;
|
nuclear@5
|
93 case 2:
|
nuclear@5
|
94 default:
|
nuclear@5
|
95 log_level = LogMask_All;
|
nuclear@5
|
96 break;
|
nuclear@5
|
97 }
|
nuclear@5
|
98 }
|
nuclear@5
|
99
|
nuclear@5
|
100 System::Init(Log::ConfigureDefaultLog(log_level));
|
nuclear@3
|
101 if(!(vr_ctx.ovr_devman = DeviceManager::Create())) {
|
nuclear@1
|
102 fprintf(stderr, "failed to create OVR device manager\n");
|
nuclear@1
|
103 return false;
|
nuclear@1
|
104 }
|
nuclear@1
|
105
|
nuclear@1
|
106 // create the display device
|
nuclear@4
|
107 HMDInfo info;
|
nuclear@3
|
108 if(!(vr_ctx.ovr_hmd_dev = vr_ctx.ovr_devman->EnumerateDevices<HMDDevice>().CreateDevice())) {
|
nuclear@1
|
109 fprintf(stderr, "no oculus rift devices found\n");
|
nuclear@4
|
110 } else {
|
nuclear@4
|
111 if(vr_ctx.ovr_hmd_dev->GetDeviceInfo(&info)) {
|
nuclear@4
|
112 printf("oculus device info:\n");
|
nuclear@4
|
113 printf(" name: %s\n", info.DisplayDeviceName);
|
nuclear@4
|
114 printf(" ipd: %f\n", info.InterpupillaryDistance);
|
nuclear@4
|
115 printf(" distortion: %f %f %f %f\n", info.DistortionK[0],
|
nuclear@4
|
116 info.DistortionK[1], info.DistortionK[2], info.DistortionK[3]);
|
nuclear@4
|
117 }
|
nuclear@1
|
118
|
nuclear@4
|
119 // calculate and store viewing parameters
|
nuclear@4
|
120 vr_ctx.info.width = info.HResolution;
|
nuclear@4
|
121 vr_ctx.info.height = info.VResolution;
|
nuclear@4
|
122 vr_ctx.info.aspect = (float)vr_ctx.info.width / (float)vr_ctx.info.height;
|
nuclear@4
|
123
|
nuclear@4
|
124 vr_ctx.info.ipd = info.InterpupillaryDistance;
|
nuclear@4
|
125 for(int i=0; i<4; i++) {
|
nuclear@4
|
126 vr_ctx.info.distort[i] = info.DistortionK[i];
|
nuclear@4
|
127 }
|
nuclear@12
|
128
|
nuclear@14
|
129 Util::Render::StereoConfig stereohelp;
|
nuclear@14
|
130 stereohelp.SetFullViewport(Util::Render::Viewport(0, 0, vr_ctx.info.width, vr_ctx.info.height));
|
nuclear@14
|
131 stereohelp.SetStereoMode(Util::Render::Stereo_LeftRight_Multipass);
|
nuclear@14
|
132 stereohelp.SetHMDInfo(info);
|
nuclear@14
|
133 stereohelp.SetDistortionFitPointVP(-1.0, 0.0);
|
nuclear@14
|
134
|
nuclear@14
|
135 vr_ctx.info.scale = stereohelp.GetDistortionScale();
|
nuclear@13
|
136
|
nuclear@13
|
137 float vhalfsz = vr_ctx.info.scale * info.VScreenSize * 0.5;
|
nuclear@13
|
138 vr_ctx.info.fov = 2.0 * atan(vhalfsz / info.EyeToScreenDistance);
|
nuclear@13
|
139
|
nuclear@13
|
140 vr_ctx.info.lens_center_offset = 0.5 - info.LensSeparationDistance / info.HScreenSize;
|
nuclear@13
|
141
|
nuclear@13
|
142 // calculate center of projection shift to match the lens positions
|
nuclear@13
|
143 float center_dist_meters = info.HScreenSize * 0.25;
|
nuclear@13
|
144 float proj_shift = center_dist_meters - info.LensSeparationDistance * 0.5;
|
nuclear@13
|
145 vr_ctx.info.proj_center_offset = 4.0 * proj_shift / info.HScreenSize;
|
nuclear@15
|
146
|
nuclear@16
|
147 // grab the display info
|
nuclear@15
|
148 vr_ctx.info.display = new char[strlen(info.DisplayDeviceName) + 1];
|
nuclear@15
|
149 strcpy(vr_ctx.info.display, info.DisplayDeviceName);
|
nuclear@16
|
150
|
nuclear@16
|
151 vr_ctx.info.display_xoffs = info.DesktopX;
|
nuclear@16
|
152 vr_ctx.info.display_yoffs = info.DesktopY;
|
nuclear@16
|
153
|
nuclear@16
|
154 printf("display: \"%s\" offset: %+d %+d\n", vr_ctx.info.display,
|
nuclear@16
|
155 vr_ctx.info.display_xoffs, vr_ctx.info.display_yoffs);
|
nuclear@1
|
156 }
|
nuclear@1
|
157
|
nuclear@1
|
158 // get the sensor device
|
nuclear@4
|
159 if(vr_ctx.ovr_hmd_dev) {
|
nuclear@4
|
160 if(!(vr_ctx.ovr_sensor_dev = vr_ctx.ovr_hmd_dev->GetSensor())) {
|
nuclear@4
|
161 fprintf(stderr, "failed to get oculus sensor device\n");
|
nuclear@4
|
162 }
|
nuclear@4
|
163 } else {
|
nuclear@4
|
164 if(!(vr_ctx.ovr_sensor_dev = vr_ctx.ovr_devman->EnumerateDevices<SensorDevice>().CreateDevice())) {
|
nuclear@4
|
165 fprintf(stderr, "failed to get oculus sensor device\n");
|
nuclear@4
|
166 }
|
nuclear@1
|
167 }
|
nuclear@1
|
168
|
nuclear@4
|
169 if(vr_ctx.ovr_sensor_dev) {
|
nuclear@4
|
170 SensorInfo sinfo;
|
nuclear@4
|
171 if(vr_ctx.ovr_sensor_dev->GetDeviceInfo(&sinfo)) {
|
nuclear@4
|
172 printf("oculus sensor device info:\n");
|
nuclear@4
|
173 printf(" name: %s\n", sinfo.ProductName);
|
nuclear@4
|
174 }
|
nuclear@4
|
175
|
nuclear@4
|
176 vr_ctx.ovr_sfusion.AttachToSensor(vr_ctx.ovr_sensor_dev);
|
nuclear@1
|
177 }
|
nuclear@1
|
178 return true;
|
nuclear@1
|
179 }
|
nuclear@3
|
180
|
nuclear@13
|
181 #define EXTERNAL_SHADER
|
nuclear@13
|
182
|
nuclear@12
|
183 static bool init_sdr()
|
nuclear@12
|
184 {
|
nuclear@12
|
185 int status;
|
nuclear@12
|
186
|
nuclear@13
|
187 #ifdef EXTERNAL_SHADER
|
nuclear@17
|
188 FILE *fp = fopen("sdr/sdr.glsl", "rb");
|
nuclear@13
|
189 if(!fp) {
|
nuclear@13
|
190 perror("failed to load sdr.glsl");
|
nuclear@13
|
191 return false;
|
nuclear@13
|
192 }
|
nuclear@13
|
193 fseek(fp, 0, SEEK_END);
|
nuclear@13
|
194 long sz = ftell(fp);
|
nuclear@13
|
195 rewind(fp);
|
nuclear@13
|
196
|
nuclear@13
|
197 char *buf = (char*)alloca(sz + 1);
|
nuclear@13
|
198 fread(buf, 1, sz, fp);
|
nuclear@13
|
199 buf[sz] = 0;
|
nuclear@13
|
200 sdr_src = buf;
|
nuclear@13
|
201
|
nuclear@13
|
202 fclose(fp);
|
nuclear@13
|
203 #endif
|
nuclear@13
|
204
|
nuclear@12
|
205 unsigned int sdr = glCreateShader(GL_FRAGMENT_SHADER);
|
nuclear@12
|
206 glShaderSource(sdr, 1, &sdr_src, 0);
|
nuclear@12
|
207 glCompileShader(sdr);
|
nuclear@12
|
208 glGetShaderiv(sdr, GL_COMPILE_STATUS, &status);
|
nuclear@12
|
209 if(!status) {
|
nuclear@12
|
210 fprintf(stderr, "failed to compile distortion shader\n");
|
nuclear@14
|
211
|
nuclear@14
|
212 int loglen;
|
nuclear@14
|
213 glGetShaderiv(sdr, GL_INFO_LOG_LENGTH, &loglen);
|
nuclear@14
|
214
|
nuclear@14
|
215 if(loglen > 0) {
|
nuclear@14
|
216 char *log = (char*)alloca(loglen);
|
nuclear@14
|
217 glGetShaderInfoLog(sdr, loglen, &loglen, log);
|
nuclear@14
|
218 fprintf(stderr, "%s\n", log);
|
nuclear@14
|
219 }
|
nuclear@14
|
220
|
nuclear@12
|
221 return false;
|
nuclear@12
|
222 }
|
nuclear@12
|
223
|
nuclear@12
|
224 sdrprog = glCreateProgram();
|
nuclear@12
|
225 glAttachShader(sdrprog, sdr);
|
nuclear@12
|
226 glLinkProgram(sdrprog);
|
nuclear@12
|
227 if(!status) {
|
nuclear@12
|
228 fprintf(stderr, "failed to link distortion shader program\n");
|
nuclear@12
|
229 glDeleteShader(sdr);
|
nuclear@12
|
230 return false;
|
nuclear@12
|
231 }
|
nuclear@12
|
232
|
nuclear@12
|
233 int loc;
|
nuclear@12
|
234
|
nuclear@12
|
235 glUseProgram(sdrprog);
|
nuclear@12
|
236
|
nuclear@12
|
237 if((loc = glGetUniformLocation(sdrprog, "tex")) != -1) {
|
nuclear@12
|
238 glUniform1i(loc, 0);
|
nuclear@12
|
239 }
|
nuclear@13
|
240 if((loc = glGetUniformLocation(sdrprog, "lens_center_offset")) != -1) {
|
nuclear@13
|
241 glUniform1f(loc, 0);
|
nuclear@12
|
242 }
|
nuclear@12
|
243 if((loc = glGetUniformLocation(sdrprog, "scr_center")) != -1) {
|
nuclear@12
|
244 glUniform2f(loc, 0, 0);
|
nuclear@12
|
245 }
|
nuclear@12
|
246 if((loc = glGetUniformLocation(sdrprog, "scale")) != -1) {
|
nuclear@13
|
247 glUniform1f(loc, vr_ctx.info.scale);
|
nuclear@13
|
248 }
|
nuclear@13
|
249 if((loc = glGetUniformLocation(sdrprog, "aspect")) != -1) {
|
nuclear@13
|
250 printf("setting aspect: %f\n", vr_ctx.info.aspect / 2.0);
|
nuclear@13
|
251 glUniform1f(loc, vr_ctx.info.aspect / 2.0);
|
nuclear@12
|
252 }
|
nuclear@12
|
253 if((loc = glGetUniformLocation(sdrprog, "scale_in")) != -1) {
|
nuclear@12
|
254 glUniform2f(loc, 1, 1);
|
nuclear@12
|
255 }
|
nuclear@13
|
256 if((loc = glGetUniformLocation(sdrprog, "dist_factors")) != -1) {
|
nuclear@12
|
257 glUniform4f(loc, vr_ctx.info.distort[0], vr_ctx.info.distort[1],
|
nuclear@12
|
258 vr_ctx.info.distort[2], vr_ctx.info.distort[3]);
|
nuclear@12
|
259 }
|
nuclear@12
|
260
|
nuclear@12
|
261 return true;
|
nuclear@12
|
262 }
|
nuclear@12
|
263
|
nuclear@16
|
264 extern "C" const char *vr_get_display_name(void)
|
nuclear@16
|
265 {
|
nuclear@16
|
266 return vr_ctx.info.display;
|
nuclear@16
|
267 }
|
nuclear@16
|
268
|
nuclear@16
|
269 extern "C" void vr_get_display_pos(int *xptr, int *yptr)
|
nuclear@16
|
270 {
|
nuclear@16
|
271 *xptr = vr_ctx.info.display_xoffs;
|
nuclear@16
|
272 *yptr = vr_ctx.info.display_yoffs;
|
nuclear@16
|
273 }
|
nuclear@16
|
274
|
nuclear@3
|
275 extern "C" int vr_get_width(void)
|
nuclear@3
|
276 {
|
nuclear@3
|
277 return vr_ctx.info.width;
|
nuclear@3
|
278 }
|
nuclear@3
|
279
|
nuclear@3
|
280 extern "C" int vr_get_height(void)
|
nuclear@3
|
281 {
|
nuclear@3
|
282 return vr_ctx.info.height;
|
nuclear@3
|
283 }
|
nuclear@3
|
284
|
nuclear@3
|
285 extern "C" float vr_get_fov(void)
|
nuclear@3
|
286 {
|
nuclear@3
|
287 return vr_ctx.info.fov;
|
nuclear@3
|
288 }
|
nuclear@3
|
289
|
nuclear@3
|
290 extern "C" float vr_get_aspect(void)
|
nuclear@3
|
291 {
|
nuclear@3
|
292 return vr_ctx.info.aspect;
|
nuclear@3
|
293 }
|
nuclear@3
|
294
|
nuclear@3
|
295 extern "C" void vr_set_eyedist(float ipd)
|
nuclear@3
|
296 {
|
nuclear@3
|
297 vr_ctx.info.ipd = ipd;
|
nuclear@3
|
298 }
|
nuclear@3
|
299
|
nuclear@3
|
300 extern "C" float vr_get_eyedist(void)
|
nuclear@3
|
301 {
|
nuclear@3
|
302 return vr_ctx.info.ipd;
|
nuclear@3
|
303 }
|
nuclear@3
|
304
|
nuclear@3
|
305 extern "C" void vr_set_distort(const float *coef)
|
nuclear@3
|
306 {
|
nuclear@3
|
307 memcpy(vr_ctx.info.distort, coef, sizeof vr_ctx.info.distort);
|
nuclear@3
|
308 }
|
nuclear@3
|
309
|
nuclear@3
|
310 extern "C" void vr_get_distort(float *coef)
|
nuclear@3
|
311 {
|
nuclear@3
|
312 memcpy(coef, vr_ctx.info.distort, sizeof vr_ctx.info.distort);
|
nuclear@3
|
313 }
|
nuclear@3
|
314
|
nuclear@3
|
315 extern "C" void vr_set_prediction_sec(float dt)
|
nuclear@3
|
316 {
|
nuclear@3
|
317 vr_ctx.ovr_sfusion.SetPrediction(dt);
|
nuclear@3
|
318 }
|
nuclear@3
|
319
|
nuclear@3
|
320 extern "C" float vr_get_prediction_sec(void)
|
nuclear@3
|
321 {
|
nuclear@3
|
322 return vr_ctx.ovr_sfusion.GetPredictionDelta();
|
nuclear@3
|
323 }
|
nuclear@3
|
324
|
nuclear@13
|
325 extern "C" void vr_get_view_matrix(float *res, int eye)
|
nuclear@13
|
326 {
|
nuclear@13
|
327 // TODO
|
nuclear@13
|
328 }
|
nuclear@13
|
329
|
nuclear@13
|
330 extern "C" void vr_get_proj_matrix(float *res, int eye)
|
nuclear@13
|
331 {
|
nuclear@13
|
332 static float eye_scale[] = {0.0, 1.0, -1.0};
|
nuclear@13
|
333
|
nuclear@13
|
334 Matrix4f proj = Matrix4f::PerspectiveRH(vr_ctx.info.fov, vr_ctx.info.aspect / 2.0, 0.3, 1000.0);
|
nuclear@13
|
335 proj = Matrix4f::Translation(vr_ctx.info.proj_center_offset * eye_scale[eye], 0, 0) * proj;
|
nuclear@13
|
336
|
nuclear@13
|
337 memcpy(res, proj.M[0], 16 * sizeof(float));
|
nuclear@13
|
338 }
|
nuclear@13
|
339
|
nuclear@3
|
340 extern "C" void vr_get_translation(float *offs)
|
nuclear@3
|
341 {
|
nuclear@3
|
342 // current oculus devkit doesn't do translation
|
nuclear@3
|
343 offs[0] = offs[1] = offs[2] = 0.0f;
|
nuclear@3
|
344 }
|
nuclear@3
|
345
|
nuclear@3
|
346 extern "C" void vr_get_rotation(float *quat)
|
nuclear@3
|
347 {
|
nuclear@3
|
348 Quatf oq = vr_ctx.ovr_sfusion.GetPredictedOrientation();
|
nuclear@3
|
349 quat[0] = oq.x;
|
nuclear@3
|
350 quat[1] = oq.y;
|
nuclear@3
|
351 quat[2] = oq.z;
|
nuclear@3
|
352 quat[3] = oq.w;
|
nuclear@3
|
353 }
|
nuclear@3
|
354
|
nuclear@3
|
355 extern "C" void vr_get_rotation_euler(float *euler)
|
nuclear@3
|
356 {
|
nuclear@3
|
357 Quatf oq = vr_ctx.ovr_sfusion.GetPredictedOrientation();
|
nuclear@3
|
358 oq.GetEulerAngles<Axis_Y, Axis_X, Axis_Z>(euler + 1, euler, euler + 2);
|
nuclear@3
|
359 }
|
nuclear@12
|
360
|
nuclear@18
|
361 extern "C" void vr_draw_eye(int eye, unsigned int tex, float tex_scale_x, float tex_scale_y)
|
nuclear@12
|
362 {
|
nuclear@12
|
363 static const float rects[3][4] = {
|
nuclear@12
|
364 {-1, -1, 1, 1},
|
nuclear@12
|
365 {-1, -1, 0, 1},
|
nuclear@12
|
366 {0, -1, 1, 1}
|
nuclear@12
|
367 };
|
nuclear@21
|
368 static const float quad_trans[3] = {0, -1, 1};
|
nuclear@21
|
369 static const float quad_scale[3] = {1, 0.5, 0.5};
|
nuclear@12
|
370 static const float offs_scale[3] = {0.0, -1.0, 1.0};
|
nuclear@21
|
371 static int prev_tex_scale_x, prev_tex_scale_y;
|
nuclear@12
|
372
|
nuclear@12
|
373 glPushAttrib(GL_ENABLE_BIT);
|
nuclear@12
|
374 glDisable(GL_DEPTH_TEST);
|
nuclear@12
|
375 glDisable(GL_LIGHTING);
|
nuclear@21
|
376 glDisable(GL_CULL_FACE);
|
nuclear@21
|
377
|
nuclear@21
|
378 glMatrixMode(GL_PROJECTION);
|
nuclear@21
|
379 glPushMatrix();
|
nuclear@21
|
380 glLoadIdentity();
|
nuclear@12
|
381
|
nuclear@12
|
382 glMatrixMode(GL_MODELVIEW);
|
nuclear@12
|
383 glPushMatrix();
|
nuclear@12
|
384 glLoadIdentity();
|
nuclear@12
|
385
|
nuclear@21
|
386 if(!dbg_enable) {
|
nuclear@21
|
387 glUseProgram(sdrprog);
|
nuclear@12
|
388
|
nuclear@21
|
389 if(sdrprog) {
|
nuclear@21
|
390 int loc;
|
nuclear@21
|
391 if((loc = glGetUniformLocation(sdrprog, "lens_center_offset")) != -1) {
|
nuclear@21
|
392 float offset = vr_ctx.info.lens_center_offset * offs_scale[eye];
|
nuclear@21
|
393 glUniform1f(loc, offset);
|
nuclear@21
|
394 }
|
nuclear@12
|
395
|
nuclear@21
|
396 if((loc = glGetUniformLocation(sdrprog, "tex_scale")) != -1) {
|
nuclear@21
|
397 glUniform2f(loc, tex_scale_x, tex_scale_y);
|
nuclear@21
|
398 }
|
nuclear@13
|
399 }
|
nuclear@18
|
400
|
nuclear@21
|
401 glBindTexture(GL_TEXTURE_2D, tex);
|
nuclear@21
|
402 glBegin(GL_QUADS);
|
nuclear@21
|
403 glColor4f(1, 1, 1, 1);
|
nuclear@21
|
404 glTexCoord2f(0, 0); glVertex2f(rects[eye][0], rects[eye][1]);
|
nuclear@21
|
405 glTexCoord2f(1, 0); glVertex2f(rects[eye][2], rects[eye][1]);
|
nuclear@21
|
406 glTexCoord2f(1, 1); glVertex2f(rects[eye][2], rects[eye][3]);
|
nuclear@21
|
407 glTexCoord2f(0, 1); glVertex2f(rects[eye][0], rects[eye][3]);
|
nuclear@21
|
408 glEnd();
|
nuclear@21
|
409
|
nuclear@21
|
410 glUseProgram(0);
|
nuclear@21
|
411
|
nuclear@21
|
412 } else {
|
nuclear@21
|
413
|
nuclear@21
|
414 if(!mesh_valid || tex_scale_x != prev_tex_scale_x || tex_scale_y != prev_tex_scale_y) {
|
nuclear@21
|
415 for(int i=0; i<2; i++) {
|
nuclear@21
|
416 int eye = i + VR_EYE_LEFT;
|
nuclear@21
|
417
|
nuclear@21
|
418 if(wrapmesh[i].vbo) {
|
nuclear@21
|
419 glDeleteBuffers(1, &wrapmesh[i].vbo);
|
nuclear@21
|
420 }
|
nuclear@21
|
421 if(wrapmesh[i].ibo) {
|
nuclear@21
|
422 glDeleteBuffers(1, &wrapmesh[i].ibo);
|
nuclear@21
|
423 }
|
nuclear@21
|
424
|
nuclear@21
|
425 float aspect = vr_ctx.info.aspect / 2.0;
|
nuclear@21
|
426 float offset = vr_ctx.info.lens_center_offset * offs_scale[eye];
|
nuclear@21
|
427 wrapmesh[i] = gen_view_mesh(USUB, VSUB, aspect, offset, vr_ctx.info.scale, vr_ctx.info.distort,
|
nuclear@21
|
428 tex_scale_x, tex_scale_y);
|
nuclear@21
|
429 }
|
nuclear@21
|
430 mesh_valid = true;
|
nuclear@21
|
431 prev_tex_scale_x = tex_scale_x;
|
nuclear@21
|
432 prev_tex_scale_y = tex_scale_y;
|
nuclear@18
|
433 }
|
nuclear@21
|
434
|
nuclear@21
|
435 glScalef(quad_scale[eye], 1.0, 1.0);
|
nuclear@21
|
436 glTranslatef(quad_trans[eye], 0, 0);
|
nuclear@21
|
437
|
nuclear@21
|
438 glUseProgram(0);
|
nuclear@21
|
439 glBindTexture(GL_TEXTURE_2D, tex);
|
nuclear@21
|
440 glEnable(GL_TEXTURE_2D);
|
nuclear@21
|
441
|
nuclear@21
|
442 glColor3f(1, 1, 1);
|
nuclear@21
|
443
|
nuclear@21
|
444 glEnableClientState(GL_VERTEX_ARRAY);
|
nuclear@21
|
445 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
|
nuclear@21
|
446
|
nuclear@21
|
447 int meshidx = eye - VR_EYE_LEFT;
|
nuclear@21
|
448 glBindBuffer(GL_ARRAY_BUFFER, wrapmesh[meshidx].vbo);
|
nuclear@21
|
449 glVertexPointer(3, GL_FLOAT, sizeof(Vertex), 0);
|
nuclear@21
|
450 glTexCoordPointer(2, GL_FLOAT, sizeof(Vertex), (void*)offsetof(Vertex, tx));
|
nuclear@21
|
451
|
nuclear@21
|
452 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, wrapmesh[meshidx].ibo);
|
nuclear@21
|
453 glDrawElements(GL_TRIANGLES, wrapmesh[meshidx].num_faces * 3, GL_UNSIGNED_INT, 0);
|
nuclear@21
|
454
|
nuclear@21
|
455 glBindBuffer(GL_ARRAY_BUFFER, 0);
|
nuclear@21
|
456 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
|
nuclear@21
|
457
|
nuclear@21
|
458 glDisableClientState(GL_VERTEX_ARRAY);
|
nuclear@21
|
459 glDisableClientState(GL_TEXTURE_COORD_ARRAY);
|
nuclear@12
|
460 }
|
nuclear@12
|
461
|
nuclear@21
|
462 glMatrixMode(GL_PROJECTION);
|
nuclear@12
|
463 glPopMatrix();
|
nuclear@12
|
464 glMatrixMode(GL_MODELVIEW);
|
nuclear@12
|
465 glPopMatrix();
|
nuclear@12
|
466
|
nuclear@12
|
467 glPopAttrib();
|
nuclear@12
|
468 }
|
nuclear@21
|
469
|
nuclear@21
|
470 static Mesh gen_view_mesh(int usub, int vsub, float aspect, float lens_center_offset,
|
nuclear@21
|
471 float scale, const float *dist_factors, float tex_scale_x, float tex_scale_y)
|
nuclear@21
|
472 {
|
nuclear@21
|
473 int uverts = usub + 1;
|
nuclear@21
|
474 int vverts = vsub + 1;
|
nuclear@21
|
475
|
nuclear@21
|
476 int num_verts = uverts * vverts;
|
nuclear@21
|
477 int num_quads = usub * vsub;
|
nuclear@21
|
478 int num_tris = num_quads * 2;
|
nuclear@21
|
479
|
nuclear@21
|
480 Vertex *varr = new Vertex[num_verts];
|
nuclear@21
|
481 unsigned int *iarr = new unsigned int[num_tris * 3];
|
nuclear@21
|
482
|
nuclear@21
|
483 float du = 1.0 / (float)usub;
|
nuclear@21
|
484 float dv = 1.0 / (float)vsub;
|
nuclear@21
|
485
|
nuclear@21
|
486 Vertex *vptr = varr;
|
nuclear@21
|
487 for(int i=0; i<vverts; i++) {
|
nuclear@21
|
488 float v = (float)i * dv;
|
nuclear@21
|
489 float y = 2.0 * v - 1.0;
|
nuclear@21
|
490
|
nuclear@21
|
491 for(int j=0; j<uverts; j++) {
|
nuclear@21
|
492 float u = (float)j * du;
|
nuclear@21
|
493 float x = 2.0 * u - 1.0;
|
nuclear@21
|
494 float tc[2] = {u, v};
|
nuclear@21
|
495
|
nuclear@21
|
496 distort_texcoords(tc, aspect, lens_center_offset, scale, dist_factors);
|
nuclear@21
|
497
|
nuclear@21
|
498 vptr->x = x;
|
nuclear@21
|
499 vptr->y = y;
|
nuclear@21
|
500 vptr->z = 0;
|
nuclear@21
|
501 vptr->tx = tc[0] * tex_scale_x;
|
nuclear@21
|
502 vptr->ty = tc[1] * tex_scale_y;
|
nuclear@21
|
503 vptr++;
|
nuclear@21
|
504 }
|
nuclear@21
|
505 }
|
nuclear@21
|
506
|
nuclear@21
|
507 unsigned int *iptr = iarr;
|
nuclear@21
|
508 for(int i=0; i<vsub; i++) {
|
nuclear@21
|
509 for(int j=0; j<usub; j++) {
|
nuclear@21
|
510 *iptr++ = i * uverts + j;
|
nuclear@21
|
511 *iptr++ = (i + 1) * uverts + j;
|
nuclear@21
|
512 *iptr++ = (i + 1) * uverts + (j + 1);
|
nuclear@21
|
513
|
nuclear@21
|
514 *iptr++ = i * uverts + j;
|
nuclear@21
|
515 *iptr++ = (i + 1) * uverts + (j + 1);
|
nuclear@21
|
516 *iptr++ = i * uverts + (j + 1);
|
nuclear@21
|
517 }
|
nuclear@21
|
518 }
|
nuclear@21
|
519
|
nuclear@21
|
520 unsigned int buf[2];
|
nuclear@21
|
521 glGenBuffers(2, buf);
|
nuclear@21
|
522 glBindBuffer(GL_ARRAY_BUFFER, buf[0]);
|
nuclear@21
|
523 glBufferData(GL_ARRAY_BUFFER, num_verts * sizeof *varr, varr, GL_STATIC_DRAW);
|
nuclear@21
|
524 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buf[1]);
|
nuclear@21
|
525 glBufferData(GL_ELEMENT_ARRAY_BUFFER, num_tris * 3 * sizeof *iarr, iarr, GL_STATIC_DRAW);
|
nuclear@21
|
526
|
nuclear@21
|
527 delete [] varr;
|
nuclear@21
|
528 delete [] iarr;
|
nuclear@21
|
529
|
nuclear@21
|
530 Mesh mesh;
|
nuclear@21
|
531 mesh.prim = GL_TRIANGLES;
|
nuclear@21
|
532 mesh.num_verts = num_verts;
|
nuclear@21
|
533 mesh.num_faces = num_tris;
|
nuclear@21
|
534 mesh.vbo = buf[0];
|
nuclear@21
|
535 mesh.ibo = buf[1];
|
nuclear@21
|
536 return mesh;
|
nuclear@21
|
537 }
|
nuclear@21
|
538
|
nuclear@21
|
539 static void distort_texcoords(float *tc, float aspect, float lens_center_offset, float scale, const float *dist_factors)
|
nuclear@21
|
540 {
|
nuclear@21
|
541 // map tc [0, 1] -> [-1, 1]
|
nuclear@21
|
542 float ptx = tc[0] * 2.0 - 1.0;
|
nuclear@21
|
543 float pty = tc[1] * 2.0 - 1.0;
|
nuclear@21
|
544
|
nuclear@21
|
545 ptx += lens_center_offset * 2.0;
|
nuclear@21
|
546 pty /= aspect; // correct for aspect ratio
|
nuclear@21
|
547
|
nuclear@21
|
548 float rad = barrel_scale(ptx * ptx + pty * pty, dist_factors);
|
nuclear@21
|
549 ptx *= rad; // scale the point by the computer distortion radius
|
nuclear@21
|
550 pty *= rad;
|
nuclear@21
|
551
|
nuclear@21
|
552 ptx /= scale;
|
nuclear@21
|
553 pty /= scale;
|
nuclear@21
|
554
|
nuclear@21
|
555 pty *= aspect;
|
nuclear@21
|
556 ptx -= lens_center_offset * 2.0;
|
nuclear@21
|
557
|
nuclear@21
|
558 // map back to range [0, 1]
|
nuclear@21
|
559 tc[0] = ptx * 0.5 + 0.5;
|
nuclear@21
|
560 tc[1] = pty * 0.5 + 0.5;
|
nuclear@21
|
561 }
|
nuclear@21
|
562
|
nuclear@21
|
563 static float barrel_scale(float rad, const float *k)
|
nuclear@21
|
564 {
|
nuclear@21
|
565 float radsq = rad * rad;
|
nuclear@21
|
566 float radquad = radsq * radsq;
|
nuclear@21
|
567 return k[0] + k[1] * radsq + k[2] * radquad + k[3] * radquad * radsq;
|
nuclear@21
|
568 }
|