openvr_test1

annotate src/app.cc @ 0:806d30b46748

OpenVR test initial commit
author John Tsiombikas <nuclear@member.fsf.org>
date Wed, 13 Apr 2016 09:39:37 +0300
parents
children
rev   line source
nuclear@0 1 #include <stdio.h>
nuclear@0 2 #include <assert.h>
nuclear@0 3 #include <GL/glew.h>
nuclear@0 4 #include <openvr.h>
nuclear@0 5 #include <gmath/gmath.h>
nuclear@0 6 #include "app.h"
nuclear@0 7
nuclear@0 8 using namespace vr; // OpenVR namespace
nuclear@0 9
nuclear@0 10 static void draw_scene();
nuclear@0 11 static void draw_box(float xsz, float ysz, float zsz, float norm_sign);
nuclear@0 12 static Mat4 openvr_matrix4(const HmdMatrix44_t &mat);
nuclear@0 13 static Mat4 openvr_matrix(const HmdMatrix34_t &mat);
nuclear@0 14 static VRTextureBounds_t openvr_tex_bounds(float umin, float vmin, float umax, float vmax);
nuclear@0 15 static void update_rtarg(int width, int height);
nuclear@0 16 static unsigned int next_pow2(unsigned int x);
nuclear@0 17 static unsigned int gen_chess_tex(float r0, float g0, float b0, float r1, float g1, float b1);
nuclear@0 18
nuclear@0 19 static int win_width, win_height;
nuclear@0 20
nuclear@0 21 static unsigned int fbo, fb_tex, fb_depth;
nuclear@0 22 static int fb_width, fb_height;
nuclear@0 23 static int fb_tex_width, fb_tex_height;
nuclear@0 24
nuclear@0 25 static unsigned int chess_tex;
nuclear@0 26
nuclear@0 27 // openvr stuff
nuclear@0 28 static IVRSystem *vrsys;
nuclear@0 29 static IVRCompositor *vrcomp;
nuclear@0 30 static bool vrdev_state[k_unMaxTrackedDeviceCount];
nuclear@0 31 static TrackedDevicePose_t vrdev_pose[k_unMaxTrackedDeviceCount];
nuclear@0 32 static Mat4 eye_matrix[2];
nuclear@0 33 static Mat4 proj_matrix[2];
nuclear@0 34 static Texture_t vrtex = {0, API_OpenGL, ColorSpace_Linear};
nuclear@0 35 static VRTextureBounds_t vrtex_bounds[2];
nuclear@0 36
nuclear@0 37 bool app_init()
nuclear@0 38 {
nuclear@0 39 glewInit();
nuclear@0 40
nuclear@0 41 glEnable(GL_DEPTH_TEST);
nuclear@0 42 glEnable(GL_CULL_FACE);
nuclear@0 43 glEnable(GL_LIGHTING);
nuclear@0 44 glEnable(GL_LIGHT0);
nuclear@0 45 glEnable(GL_LIGHT1);
nuclear@0 46 glEnable(GL_NORMALIZE);
nuclear@0 47
nuclear@0 48 glClearColor(0.1, 0.1, 0.1, 1);
nuclear@0 49
nuclear@0 50 chess_tex = gen_chess_tex(1.0, 0.7, 0.4, 0.4, 0.7, 1.0);
nuclear@0 51
nuclear@0 52 // Initialize OpenVR
nuclear@0 53 EVRInitError vrerr;
nuclear@0 54 if(!(vrsys = VR_Init(&vrerr, VRApplication_Scene))) {
nuclear@0 55 fprintf(stderr, "failed to initialize OpenVR: %s\n",
nuclear@0 56 VR_GetVRInitErrorAsEnglishDescription(vrerr));
nuclear@0 57 return false;
nuclear@0 58 }
nuclear@0 59 if(!(vrcomp = VRCompositor())) {
nuclear@0 60 fprintf(stderr, "failed to initialize OpenVR compositor\n");
nuclear@0 61 return false;
nuclear@0 62 }
nuclear@0 63
nuclear@0 64 uint32_t xsz, ysz;
nuclear@0 65 vrsys->GetRecommendedRenderTargetSize(&xsz, &ysz);
nuclear@0 66 fb_width = xsz * 2;
nuclear@0 67 fb_height = ysz;
nuclear@0 68 update_rtarg(fb_width, fb_height); // create render target
nuclear@0 69
nuclear@0 70 for(int i=0; i<2; i++) {
nuclear@0 71 EVREye eye = i == 0 ? Eye_Left : Eye_Right;
nuclear@0 72
nuclear@0 73 // projection matrix for each eye
nuclear@0 74 proj_matrix[i] = openvr_matrix4(vrsys->GetProjectionMatrix(eye, 0.5, 500.0, API_OpenGL));
nuclear@0 75 // eye (relative to head) matrix
nuclear@0 76 eye_matrix[i] = openvr_matrix(vrsys->GetEyeToHeadTransform(eye));
nuclear@0 77 }
nuclear@0 78
nuclear@0 79 // XXX this doesn't seem to work correctly for some reason
nuclear@0 80 //vrcomp->ShowMirrorWindow();
nuclear@0 81
nuclear@0 82 assert(glGetError() == GL_NO_ERROR);
nuclear@0 83 return true;
nuclear@0 84 }
nuclear@0 85
nuclear@0 86 void app_shutdown()
nuclear@0 87 {
nuclear@0 88 // if we call VR_Shutdown while a frame is pending, we'll crash
nuclear@0 89 vrcomp->ClearLastSubmittedFrame();
nuclear@0 90 VR_Shutdown();
nuclear@0 91 }
nuclear@0 92
nuclear@0 93 static void update()
nuclear@0 94 {
nuclear@0 95 // process OpenVR events (TODO: I think there are more events to handle)
nuclear@0 96 VREvent_t ev;
nuclear@0 97 while(vrsys->PollNextEvent(&ev, sizeof ev)) {
nuclear@0 98 switch(ev.eventType) {
nuclear@0 99 case VREvent_TrackedDeviceActivated:
nuclear@0 100 printf("Device %u activated\n", ev.trackedDeviceIndex);
nuclear@0 101 break;
nuclear@0 102
nuclear@0 103 case VREvent_TrackedDeviceDeactivated:
nuclear@0 104 printf("Device %u lost\n", ev.trackedDeviceIndex);
nuclear@0 105 break;
nuclear@0 106
nuclear@0 107 case VREvent_TrackedDeviceUpdated:
nuclear@0 108 printf("Device %u updated(?)\n", ev.trackedDeviceIndex);
nuclear@0 109 break;
nuclear@0 110 }
nuclear@0 111 }
nuclear@0 112
nuclear@0 113 // TODO implement controllers
nuclear@0 114 for(int i=0; i<k_unMaxTrackedDeviceCount; i++) {
nuclear@0 115 VRControllerState_t st;
nuclear@0 116 if(vrsys->GetControllerState(i, &st)) {
nuclear@0 117 // XXX ?
nuclear@0 118 vrdev_state[i] = st.ulButtonPressed == 0;
nuclear@0 119 }
nuclear@0 120 }
nuclear@0 121
nuclear@0 122 // this will probably block at some point... investigate further
nuclear@0 123 vrcomp->WaitGetPoses(vrdev_pose, k_unMaxTrackedDeviceCount, 0, 0);
nuclear@0 124 }
nuclear@0 125
nuclear@0 126 void app_draw()
nuclear@0 127 {
nuclear@0 128 update();
nuclear@0 129
nuclear@0 130 glBindFramebuffer(GL_FRAMEBUFFER, fbo);
nuclear@0 131 glClearColor(0, 0, 0, 1);
nuclear@0 132 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
nuclear@0 133
nuclear@0 134 for(int i=0; i<2; i++) {
nuclear@0 135 EVREye eye = i == 0 ? Eye_Left : Eye_Right;
nuclear@0 136
nuclear@0 137 glViewport(i == 0 ? 0 : fb_width / 2, 0, fb_width / 2, fb_height);
nuclear@0 138
nuclear@0 139 glMatrixMode(GL_PROJECTION);
nuclear@0 140 glLoadMatrixf(proj_matrix[i][0]);
nuclear@0 141
nuclear@0 142 Mat4 hmd_mat = openvr_matrix(vrdev_pose[k_unTrackedDeviceIndex_Hmd].mDeviceToAbsoluteTracking);
nuclear@0 143 Mat4 view_mat = inverse(eye_matrix[i] * hmd_mat);
nuclear@0 144
nuclear@0 145 glMatrixMode(GL_MODELVIEW);
nuclear@0 146 glLoadMatrixf(view_mat[0]);
nuclear@0 147
nuclear@0 148 draw_scene();
nuclear@0 149 vrcomp->Submit(eye, &vrtex, vrtex_bounds + i);
nuclear@0 150 }
nuclear@0 151 /* this is supposed to tell the compositor to get on with showing the frame without waiting for
nuclear@0 152 * the next WaitGetPoses call.
nuclear@0 153 */
nuclear@0 154 vrcomp->PostPresentHandoff();
nuclear@0 155
nuclear@0 156 glUseProgram(0);
nuclear@0 157
nuclear@0 158 // render window output
nuclear@0 159 glBindFramebuffer(GL_FRAMEBUFFER, 0);
nuclear@0 160 glViewport(0, 0, win_width, win_height);
nuclear@0 161
nuclear@0 162 glMatrixMode(GL_PROJECTION);
nuclear@0 163 glLoadIdentity();
nuclear@0 164 glMatrixMode(GL_MODELVIEW);
nuclear@0 165 glLoadIdentity();
nuclear@0 166
nuclear@0 167 glPushAttrib(GL_ENABLE_BIT);
nuclear@0 168 glBindTexture(GL_TEXTURE_2D, fb_tex);
nuclear@0 169 glEnable(GL_TEXTURE_2D);
nuclear@0 170 glDisable(GL_LIGHTING);
nuclear@0 171 glDisable(GL_DEPTH_TEST);
nuclear@0 172
nuclear@0 173 glBegin(GL_QUADS);
nuclear@0 174 float umax = (float)fb_width / fb_tex_width;
nuclear@0 175 float vmax = (float)fb_height / fb_tex_height;
nuclear@0 176 glTexCoord2f(0, 0); glVertex2f(-1, -1);
nuclear@0 177 glTexCoord2f(umax, 0); glVertex2f(1, -1);
nuclear@0 178 glTexCoord2f(umax, vmax); glVertex2f(1, 1);
nuclear@0 179 glTexCoord2f(0, vmax); glVertex2f(-1, 1);
nuclear@0 180 glEnd();
nuclear@0 181
nuclear@0 182 glPopAttrib();
nuclear@0 183
nuclear@0 184 app_swap_buffers();
nuclear@0 185 }
nuclear@0 186
nuclear@0 187 void app_reshape(int x, int y)
nuclear@0 188 {
nuclear@0 189 win_width = x;
nuclear@0 190 win_height = y;
nuclear@0 191 glViewport(0, 0, x, y);
nuclear@0 192
nuclear@0 193 glMatrixMode(GL_PROJECTION);
nuclear@0 194 glLoadIdentity();
nuclear@0 195 gluPerspective(50, (float)x / (float)y, 0.5, 500.0);
nuclear@0 196 }
nuclear@0 197
nuclear@0 198 static void draw_scene(void)
nuclear@0 199 {
nuclear@0 200 float grey[] = {0.8, 0.8, 0.8, 1};
nuclear@0 201 float col[] = {0, 0, 0, 1};
nuclear@0 202 float lpos[][4] = {
nuclear@0 203 {-8, 2, 10, 1},
nuclear@0 204 {0, 15, 0, 1}
nuclear@0 205 };
nuclear@0 206 float lcol[][4] = {
nuclear@0 207 {0.8, 0.8, 0.8, 1},
nuclear@0 208 {0.4, 0.3, 0.3, 1}
nuclear@0 209 };
nuclear@0 210
nuclear@0 211 for(int i=0; i<2; i++) {
nuclear@0 212 glLightfv(GL_LIGHT0 + i, GL_POSITION, lpos[i]);
nuclear@0 213 glLightfv(GL_LIGHT0 + i, GL_DIFFUSE, lcol[i]);
nuclear@0 214 }
nuclear@0 215
nuclear@0 216 glMatrixMode(GL_MODELVIEW);
nuclear@0 217
nuclear@0 218 glPushMatrix();
nuclear@0 219 glTranslatef(0, 10, 0);
nuclear@0 220 glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, grey);
nuclear@0 221 glBindTexture(GL_TEXTURE_2D, chess_tex);
nuclear@0 222 glEnable(GL_TEXTURE_2D);
nuclear@0 223 draw_box(30, 20, 30, -1.0);
nuclear@0 224 glDisable(GL_TEXTURE_2D);
nuclear@0 225 glPopMatrix();
nuclear@0 226
nuclear@0 227 for(int i=0; i<4; i++) {
nuclear@0 228 glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, grey);
nuclear@0 229 glPushMatrix();
nuclear@0 230 glTranslatef(i & 1 ? 5 : -5, 1, i & 2 ? -5 : 5);
nuclear@0 231 draw_box(0.5, 2, 0.5, 1.0);
nuclear@0 232 glPopMatrix();
nuclear@0 233
nuclear@0 234 col[0] = i & 1 ? 1.0 : 0.3;
nuclear@0 235 col[1] = i == 0 ? 1.0 : 0.3;
nuclear@0 236 col[2] = i & 2 ? 1.0 : 0.3;
nuclear@0 237 glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, col);
nuclear@0 238
nuclear@0 239 glPushMatrix();
nuclear@0 240 if(i & 1) {
nuclear@0 241 glTranslatef(0, 0.25, i & 2 ? 2 : -2);
nuclear@0 242 } else {
nuclear@0 243 glTranslatef(i & 2 ? 2 : -2, 0.25, 0);
nuclear@0 244 }
nuclear@0 245 draw_box(0.5, 0.5, 0.5, 1.0);
nuclear@0 246 glPopMatrix();
nuclear@0 247 }
nuclear@0 248
nuclear@0 249 col[0] = 1;
nuclear@0 250 col[1] = 1;
nuclear@0 251 col[2] = 0.4;
nuclear@0 252 glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, col);
nuclear@0 253 draw_box(0.05, 1.2, 6, 1.0);
nuclear@0 254 draw_box(6, 1.2, 0.05, 1.0);
nuclear@0 255 }
nuclear@0 256
nuclear@0 257 static void draw_box(float xsz, float ysz, float zsz, float norm_sign)
nuclear@0 258 {
nuclear@0 259 glMatrixMode(GL_MODELVIEW);
nuclear@0 260 glPushMatrix();
nuclear@0 261 glScalef(xsz * 0.5, ysz * 0.5, zsz * 0.5);
nuclear@0 262
nuclear@0 263 if(norm_sign < 0.0) {
nuclear@0 264 glFrontFace(GL_CW);
nuclear@0 265 }
nuclear@0 266
nuclear@0 267 glBegin(GL_QUADS);
nuclear@0 268 glNormal3f(0, 0, 1 * norm_sign);
nuclear@0 269 glTexCoord2f(0, 0); glVertex3f(-1, -1, 1);
nuclear@0 270 glTexCoord2f(1, 0); glVertex3f(1, -1, 1);
nuclear@0 271 glTexCoord2f(1, 1); glVertex3f(1, 1, 1);
nuclear@0 272 glTexCoord2f(0, 1); glVertex3f(-1, 1, 1);
nuclear@0 273 glNormal3f(1 * norm_sign, 0, 0);
nuclear@0 274 glTexCoord2f(0, 0); glVertex3f(1, -1, 1);
nuclear@0 275 glTexCoord2f(1, 0); glVertex3f(1, -1, -1);
nuclear@0 276 glTexCoord2f(1, 1); glVertex3f(1, 1, -1);
nuclear@0 277 glTexCoord2f(0, 1); glVertex3f(1, 1, 1);
nuclear@0 278 glNormal3f(0, 0, -1 * norm_sign);
nuclear@0 279 glTexCoord2f(0, 0); glVertex3f(1, -1, -1);
nuclear@0 280 glTexCoord2f(1, 0); glVertex3f(-1, -1, -1);
nuclear@0 281 glTexCoord2f(1, 1); glVertex3f(-1, 1, -1);
nuclear@0 282 glTexCoord2f(0, 1); glVertex3f(1, 1, -1);
nuclear@0 283 glNormal3f(-1 * norm_sign, 0, 0);
nuclear@0 284 glTexCoord2f(0, 0); glVertex3f(-1, -1, -1);
nuclear@0 285 glTexCoord2f(1, 0); glVertex3f(-1, -1, 1);
nuclear@0 286 glTexCoord2f(1, 1); glVertex3f(-1, 1, 1);
nuclear@0 287 glTexCoord2f(0, 1); glVertex3f(-1, 1, -1);
nuclear@0 288 glEnd();
nuclear@0 289 glBegin(GL_TRIANGLE_FAN);
nuclear@0 290 glNormal3f(0, 1 * norm_sign, 0);
nuclear@0 291 glTexCoord2f(0.5, 0.5); glVertex3f(0, 1, 0);
nuclear@0 292 glTexCoord2f(0, 0); glVertex3f(-1, 1, 1);
nuclear@0 293 glTexCoord2f(1, 0); glVertex3f(1, 1, 1);
nuclear@0 294 glTexCoord2f(1, 1); glVertex3f(1, 1, -1);
nuclear@0 295 glTexCoord2f(0, 1); glVertex3f(-1, 1, -1);
nuclear@0 296 glTexCoord2f(0, 0); glVertex3f(-1, 1, 1);
nuclear@0 297 glEnd();
nuclear@0 298 glBegin(GL_TRIANGLE_FAN);
nuclear@0 299 glNormal3f(0, -1 * norm_sign, 0);
nuclear@0 300 glTexCoord2f(0.5, 0.5); glVertex3f(0, -1, 0);
nuclear@0 301 glTexCoord2f(0, 0); glVertex3f(-1, -1, -1);
nuclear@0 302 glTexCoord2f(1, 0); glVertex3f(1, -1, -1);
nuclear@0 303 glTexCoord2f(1, 1); glVertex3f(1, -1, 1);
nuclear@0 304 glTexCoord2f(0, 1); glVertex3f(-1, -1, 1);
nuclear@0 305 glTexCoord2f(0, 0); glVertex3f(-1, -1, -1);
nuclear@0 306 glEnd();
nuclear@0 307
nuclear@0 308 glFrontFace(GL_CCW);
nuclear@0 309 glPopMatrix();
nuclear@0 310 }
nuclear@0 311
nuclear@0 312 static Mat4 openvr_matrix4(const HmdMatrix44_t &mat)
nuclear@0 313 {
nuclear@0 314 return Mat4(mat.m[0][0], mat.m[1][0], mat.m[2][0], mat.m[3][0],
nuclear@0 315 mat.m[0][1], mat.m[1][1], mat.m[2][1], mat.m[3][1],
nuclear@0 316 mat.m[0][2], mat.m[1][2], mat.m[2][2], mat.m[3][2],
nuclear@0 317 mat.m[0][3], mat.m[1][3], mat.m[2][3], mat.m[3][3]);
nuclear@0 318 }
nuclear@0 319
nuclear@0 320 static Mat4 openvr_matrix(const HmdMatrix34_t &mat)
nuclear@0 321 {
nuclear@0 322 return Mat4(mat.m[0][0], mat.m[1][0], mat.m[2][0], 0,
nuclear@0 323 mat.m[0][1], mat.m[1][1], mat.m[2][1], 0,
nuclear@0 324 mat.m[0][2], mat.m[1][2], mat.m[2][2], 0,
nuclear@0 325 mat.m[0][3], mat.m[1][3], mat.m[2][3], 1);
nuclear@0 326 }
nuclear@0 327
nuclear@0 328 static VRTextureBounds_t openvr_tex_bounds(float umin, float vmin, float umax, float vmax)
nuclear@0 329 {
nuclear@0 330 VRTextureBounds_t res;
nuclear@0 331 res.uMin = umin;
nuclear@0 332 res.uMax = umax;
nuclear@0 333 res.vMin = vmin;
nuclear@0 334 res.vMax = vmax;
nuclear@0 335 return res;
nuclear@0 336 }
nuclear@0 337
nuclear@0 338 /* update_rtarg creates (and/or resizes) the render target used to draw the two stero views */
nuclear@0 339 static void update_rtarg(int width, int height)
nuclear@0 340 {
nuclear@0 341 if(!fbo) {
nuclear@0 342 /* if fbo does not exist, then nothing does... create every opengl object */
nuclear@0 343 glGenFramebuffers(1, &fbo);
nuclear@0 344 glGenTextures(1, &fb_tex);
nuclear@0 345 glGenRenderbuffers(1, &fb_depth);
nuclear@0 346
nuclear@0 347 glBindTexture(GL_TEXTURE_2D, fb_tex);
nuclear@0 348 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
nuclear@0 349 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
nuclear@0 350 }
nuclear@0 351
nuclear@0 352 glBindFramebuffer(GL_FRAMEBUFFER, fbo);
nuclear@0 353
nuclear@0 354 /* calculate the next power of two in both dimensions and use that as a texture size */
nuclear@0 355 fb_tex_width = next_pow2(width);
nuclear@0 356 fb_tex_height = next_pow2(height);
nuclear@0 357
nuclear@0 358 /* create and attach the texture that will be used as a color buffer */
nuclear@0 359 glBindTexture(GL_TEXTURE_2D, fb_tex);
nuclear@0 360 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, fb_tex_width, fb_tex_height, 0,
nuclear@0 361 GL_RGBA, GL_UNSIGNED_BYTE, 0);
nuclear@0 362 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, fb_tex, 0);
nuclear@0 363
nuclear@0 364 /* create and attach the renderbuffer that will serve as our z-buffer */
nuclear@0 365 glBindRenderbuffer(GL_RENDERBUFFER, fb_depth);
nuclear@0 366 glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, fb_tex_width, fb_tex_height);
nuclear@0 367 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, fb_depth);
nuclear@0 368
nuclear@0 369 if(glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
nuclear@0 370 fprintf(stderr, "incomplete framebuffer!\n");
nuclear@0 371 }
nuclear@0 372
nuclear@0 373 glBindFramebuffer(GL_FRAMEBUFFER, 0);
nuclear@0 374 printf("created render target: %dx%d (texture size: %dx%d)\n", width, height, fb_tex_width, fb_tex_height);
nuclear@0 375
nuclear@0 376 /* update the OpenVR texture descriptors */
nuclear@0 377 vrtex.handle = (void*)fb_tex;
nuclear@0 378 float umax = (float)fb_width / fb_tex_width;
nuclear@0 379 float vmax = (float)fb_height / fb_tex_height;
nuclear@0 380 vrtex_bounds[0] = openvr_tex_bounds(0, 1.0 - vmax, 0.5 * umax, 1.0);
nuclear@0 381 vrtex_bounds[1] = openvr_tex_bounds(0.5 * umax, 1.0 - vmax, umax, 1.0);
nuclear@0 382 }
nuclear@0 383
nuclear@0 384
nuclear@0 385 void app_keyboard(int key, bool pressed)
nuclear@0 386 {
nuclear@0 387 if(pressed) {
nuclear@0 388 switch(key) {
nuclear@0 389 case 27:
nuclear@0 390 app_quit();
nuclear@0 391 break;
nuclear@0 392
nuclear@0 393 case ' ':
nuclear@0 394 case 'r':
nuclear@0 395 vrsys->ResetSeatedZeroPose();
nuclear@0 396 break;
nuclear@0 397
nuclear@0 398 default:
nuclear@0 399 break;
nuclear@0 400 }
nuclear@0 401 }
nuclear@0 402 }
nuclear@0 403
nuclear@0 404 static unsigned int next_pow2(unsigned int x)
nuclear@0 405 {
nuclear@0 406 x -= 1;
nuclear@0 407 x |= x >> 1;
nuclear@0 408 x |= x >> 2;
nuclear@0 409 x |= x >> 4;
nuclear@0 410 x |= x >> 8;
nuclear@0 411 x |= x >> 16;
nuclear@0 412 return x + 1;
nuclear@0 413 }
nuclear@0 414
nuclear@0 415 /* generate a chessboard texture with tiles colored (r0, g0, b0) and (r1, g1, b1) */
nuclear@0 416 unsigned int gen_chess_tex(float r0, float g0, float b0, float r1, float g1, float b1)
nuclear@0 417 {
nuclear@0 418 unsigned int tex;
nuclear@0 419 unsigned char img[8 * 8 * 3];
nuclear@0 420 unsigned char *pix = img;
nuclear@0 421
nuclear@0 422 for(int i=0; i<8; i++) {
nuclear@0 423 for(int j=0; j<8; j++) {
nuclear@0 424 int black = (i & 1) == (j & 1);
nuclear@0 425 pix[0] = (black ? r0 : r1) * 255;
nuclear@0 426 pix[1] = (black ? g0 : g1) * 255;
nuclear@0 427 pix[2] = (black ? b0 : b1) * 255;
nuclear@0 428 pix += 3;
nuclear@0 429 }
nuclear@0 430 }
nuclear@0 431
nuclear@0 432 glGenTextures(1, &tex);
nuclear@0 433 glBindTexture(GL_TEXTURE_2D, tex);
nuclear@0 434 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
nuclear@0 435 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
nuclear@0 436 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 8, 8, 0, GL_RGB, GL_UNSIGNED_BYTE, img);
nuclear@0 437
nuclear@0 438 return tex;
nuclear@0 439 }