oculus1

annotate src/vr.cc @ 21:ef4c9d8eeca7

added shaderless distortion method
author John Tsiombikas <nuclear@member.fsf.org>
date Wed, 02 Oct 2013 04:09:37 +0300
parents 899cf9ebffb4
children 75ab0d4ce2bb
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 }