libgoatvr

annotate example/src/main.c @ 8:3d9ec6fe97d7

- added distortion mesh generation for the OpenHMD module (unfinished) - changed internal implementation function naming to use the vrimp_ prefix - added an opengl helper function to load extension entry points
author John Tsiombikas <nuclear@member.fsf.org>
date Sat, 20 Sep 2014 13:22:53 +0300
parents b71314e80654
children 34d4643d61f9
rev   line source
nuclear@5 1 #include <stdio.h>
nuclear@5 2 #include <stdlib.h>
nuclear@5 3 #include <assert.h>
nuclear@5 4 #include <SDL2/SDL.h>
nuclear@5 5 #include <GL/glew.h>
nuclear@5 6 #include "vr.h"
nuclear@5 7
nuclear@5 8 int init(void);
nuclear@5 9 void cleanup(void);
nuclear@5 10 void toggle_hmd_fullscreen(void);
nuclear@5 11 void display(void);
nuclear@5 12 void draw_scene(void);
nuclear@5 13 void draw_box(float xsz, float ysz, float zsz, float norm_sign);
nuclear@5 14 void update_rtarg(int width, int height);
nuclear@5 15 int handle_event(SDL_Event *ev);
nuclear@5 16 int key_event(int key, int state);
nuclear@5 17 void reshape(int x, int y);
nuclear@5 18 unsigned int next_pow2(unsigned int x);
nuclear@5 19 void quat_to_matrix(const float *quat, float *mat);
nuclear@5 20 unsigned int gen_chess_tex(float r0, float g0, float b0, float r1, float g1, float b1);
nuclear@5 21
nuclear@5 22 static SDL_Window *win;
nuclear@5 23 static SDL_GLContext ctx;
nuclear@5 24 static int win_width, win_height;
nuclear@5 25
nuclear@5 26 static unsigned int fbo, fb_tex, fb_depth;
nuclear@5 27 static int fb_width, fb_height;
nuclear@5 28 static int fb_tex_width, fb_tex_height;
nuclear@5 29
nuclear@5 30 static unsigned int chess_tex;
nuclear@5 31
nuclear@5 32
nuclear@5 33 int main(int argc, char **argv)
nuclear@5 34 {
nuclear@5 35 if(init() == -1) {
nuclear@5 36 return 1;
nuclear@5 37 }
nuclear@5 38
nuclear@5 39 for(;;) {
nuclear@5 40 SDL_Event ev;
nuclear@5 41 while(SDL_PollEvent(&ev)) {
nuclear@5 42 if(handle_event(&ev) == -1) {
nuclear@5 43 goto done;
nuclear@5 44 }
nuclear@5 45 }
nuclear@5 46 display();
nuclear@5 47 }
nuclear@5 48
nuclear@5 49 done:
nuclear@5 50 cleanup();
nuclear@5 51 return 0;
nuclear@5 52 }
nuclear@5 53
nuclear@5 54
nuclear@5 55 int init(void)
nuclear@5 56 {
nuclear@5 57 int x, y;
nuclear@5 58 unsigned int flags;
nuclear@5 59
nuclear@5 60 SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER);
nuclear@5 61
nuclear@5 62 x = y = SDL_WINDOWPOS_UNDEFINED;
nuclear@5 63 flags = SDL_WINDOW_OPENGL;
nuclear@5 64 if(!(win = SDL_CreateWindow("press 'f' to move to the HMD", x, y, 1280, 800, flags))) {
nuclear@5 65 fprintf(stderr, "failed to create window\n");
nuclear@5 66 return -1;
nuclear@5 67 }
nuclear@5 68 if(!(ctx = SDL_GL_CreateContext(win))) {
nuclear@5 69 fprintf(stderr, "failed to create OpenGL context\n");
nuclear@5 70 return -1;
nuclear@5 71 }
nuclear@5 72
nuclear@5 73 glewInit();
nuclear@5 74
nuclear@5 75 if(vr_init() == -1) {
nuclear@5 76 return -1;
nuclear@5 77 }
nuclear@5 78
nuclear@5 79 /* resize our window to match the HMD resolution */
nuclear@5 80 win_width = vr_get_opti(VR_OPT_DISPLAY_WIDTH);
nuclear@5 81 win_height = vr_get_opti(VR_OPT_DISPLAY_HEIGHT);
nuclear@5 82 if(!win_width || !win_height) {
nuclear@5 83 SDL_GetWindowSize(win, &win_width, &win_height);
nuclear@5 84 } else {
nuclear@5 85 SDL_SetWindowSize(win, win_width, win_height);
nuclear@5 86 SDL_SetWindowPosition(win, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED);
nuclear@5 87 }
nuclear@5 88
nuclear@5 89 /* and create a single render target texture to encompass both eyes */
nuclear@5 90 fb_width = vr_get_opti(VR_OPT_LEYE_XRES) + vr_get_opti(VR_OPT_REYE_XRES);
nuclear@5 91 fb_height = vr_get_opti(VR_OPT_LEYE_YRES); /* assuming both are the same */
nuclear@5 92 if(!fb_width || !fb_height) {
nuclear@5 93 fb_width = win_width;
nuclear@5 94 fb_height = win_height;
nuclear@5 95 }
nuclear@5 96 update_rtarg(fb_width, fb_height);
nuclear@5 97
nuclear@5 98 /* set our render texture and its active area */
nuclear@6 99 vr_output_texture(fb_tex, 0, 0, (float)fb_width / (float)fb_tex_width, (float)fb_height / (float)fb_tex_height);
nuclear@5 100
nuclear@5 101 glEnable(GL_DEPTH_TEST);
nuclear@5 102 glEnable(GL_CULL_FACE);
nuclear@5 103 glEnable(GL_LIGHTING);
nuclear@5 104 glEnable(GL_LIGHT0);
nuclear@5 105 glEnable(GL_LIGHT1);
nuclear@5 106 glEnable(GL_NORMALIZE);
nuclear@5 107
nuclear@5 108 glClearColor(0.5, 0.1, 0.1, 1);
nuclear@5 109
nuclear@5 110 chess_tex = gen_chess_tex(1.0, 0.7, 0.4, 0.4, 0.7, 1.0);
nuclear@5 111 return 0;
nuclear@5 112 }
nuclear@5 113
nuclear@5 114 void cleanup(void)
nuclear@5 115 {
nuclear@5 116 vr_shutdown();
nuclear@5 117 SDL_Quit();
nuclear@5 118 }
nuclear@5 119
nuclear@5 120 void toggle_hmd_fullscreen(void)
nuclear@5 121 {
nuclear@5 122 static int fullscr, prev_x, prev_y;
nuclear@5 123 fullscr = !fullscr;
nuclear@5 124
nuclear@5 125 if(fullscr) {
nuclear@5 126 /* going fullscreen on the rift. save current window position, and move it
nuclear@5 127 * to the rift's part of the desktop before going fullscreen
nuclear@5 128 */
nuclear@5 129 SDL_GetWindowPosition(win, &prev_x, &prev_y);
nuclear@5 130 SDL_SetWindowPosition(win, vr_get_opti(VR_OPT_WIN_XOFFS), vr_get_opti(VR_OPT_WIN_YOFFS));
nuclear@5 131 SDL_SetWindowFullscreen(win, SDL_WINDOW_FULLSCREEN_DESKTOP);
nuclear@5 132 } else {
nuclear@5 133 /* return to windowed mode and move the window back to its original position */
nuclear@5 134 SDL_SetWindowFullscreen(win, 0);
nuclear@5 135 SDL_SetWindowPosition(win, prev_x, prev_y);
nuclear@5 136 }
nuclear@5 137 }
nuclear@5 138
nuclear@5 139 void display(void)
nuclear@5 140 {
nuclear@5 141 int i;
nuclear@8 142 float proj_mat[16] = {1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1};
nuclear@8 143 float view_mat[16] = {1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1};
nuclear@5 144
nuclear@5 145 /* start drawing onto our texture render target */
nuclear@5 146 glBindFramebuffer(GL_FRAMEBUFFER, fbo);
nuclear@5 147 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
nuclear@5 148
nuclear@5 149 /* for each eye ... */
nuclear@5 150 for(i=0; i<2; i++) {
nuclear@5 151 vr_begin(i);
nuclear@5 152
nuclear@5 153 /* -- viewport transformation --
nuclear@5 154 * setup the viewport to draw in the left half of the framebuffer when we're
nuclear@5 155 * rendering the left eye's view (0, 0, width/2, height), and in the right half
nuclear@5 156 * of the framebuffer for the right eye's view (width/2, 0, width/2, height)
nuclear@5 157 */
nuclear@5 158 glViewport(i == 0 ? 0 : fb_width / 2, 0, fb_width / 2, fb_height);
nuclear@5 159
nuclear@5 160 glMatrixMode(GL_PROJECTION);
nuclear@5 161 /* -- projection transformation --
nuclear@5 162 * we'll just have to use the projection matrix supplied by the oculus SDK for this eye
nuclear@5 163 * note that libovr matrices are the transpose of what OpenGL expects, so we have to
nuclear@5 164 * use glLoadTransposeMatrixf instead of glLoadMatrixf to load it.
nuclear@5 165 */
nuclear@5 166 if(vr_proj_matrix(i, 0.5, 500.0, proj_mat)) {
nuclear@8 167 glLoadMatrixf(proj_mat);
nuclear@5 168 } else {
nuclear@5 169 glLoadIdentity();
nuclear@5 170 gluPerspective(50.0, (float)fb_width / 2.0 / (float)fb_height, 0.5, 500.0);
nuclear@5 171 }
nuclear@5 172
nuclear@5 173 /* -- view/camera transformation --
nuclear@5 174 * we need to construct a view matrix by combining all the information provided by the oculus
nuclear@5 175 * SDK, about the position and orientation of the user's head in the world.
nuclear@5 176 */
nuclear@5 177 glMatrixMode(GL_MODELVIEW);
nuclear@5 178 vr_view_matrix(i, view_mat);
nuclear@8 179 glLoadMatrixf(view_mat);
nuclear@5 180 /* move the camera to the eye level of the user */
nuclear@5 181 glTranslatef(0, -vr_get_optf(VR_OPT_EYE_HEIGHT), 0);
nuclear@5 182
nuclear@5 183 /* finally draw the scene for this eye */
nuclear@5 184 draw_scene();
nuclear@5 185
nuclear@5 186 vr_end();
nuclear@5 187 }
nuclear@5 188
nuclear@5 189 /* after drawing both eyes into the texture render target, revert to drawing directly to the
nuclear@5 190 * display, and we call ovrHmd_EndFrame, to let the Oculus SDK draw both images properly
nuclear@5 191 * compensated for lens distortion and chromatic abberation onto the HMD screen.
nuclear@5 192 */
nuclear@5 193 glBindFramebuffer(GL_FRAMEBUFFER, 0);
nuclear@5 194 glViewport(0, 0, win_width, win_height);
nuclear@5 195
nuclear@5 196 vr_swap_buffers();
nuclear@5 197
nuclear@5 198 assert(glGetError() == GL_NO_ERROR);
nuclear@5 199 }
nuclear@5 200
nuclear@5 201 void draw_scene(void)
nuclear@5 202 {
nuclear@5 203 int i;
nuclear@5 204 float grey[] = {0.8, 0.8, 0.8, 1};
nuclear@5 205 float col[] = {0, 0, 0, 1};
nuclear@5 206 float lpos[][4] = {
nuclear@5 207 {-8, 2, 10, 1},
nuclear@5 208 {0, 15, 0, 1}
nuclear@5 209 };
nuclear@5 210 float lcol[][4] = {
nuclear@5 211 {0.8, 0.8, 0.8, 1},
nuclear@5 212 {0.4, 0.3, 0.3, 1}
nuclear@5 213 };
nuclear@5 214
nuclear@5 215 for(i=0; i<2; i++) {
nuclear@5 216 glLightfv(GL_LIGHT0 + i, GL_POSITION, lpos[i]);
nuclear@5 217 glLightfv(GL_LIGHT0 + i, GL_DIFFUSE, lcol[i]);
nuclear@5 218 }
nuclear@5 219
nuclear@5 220 glMatrixMode(GL_MODELVIEW);
nuclear@5 221
nuclear@5 222 glPushMatrix();
nuclear@5 223 glTranslatef(0, 10, 0);
nuclear@5 224 glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, grey);
nuclear@5 225 glBindTexture(GL_TEXTURE_2D, chess_tex);
nuclear@5 226 glEnable(GL_TEXTURE_2D);
nuclear@5 227 draw_box(30, 20, 30, -1.0);
nuclear@5 228 glDisable(GL_TEXTURE_2D);
nuclear@5 229 glPopMatrix();
nuclear@5 230
nuclear@5 231 for(i=0; i<4; i++) {
nuclear@5 232 glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, grey);
nuclear@5 233 glPushMatrix();
nuclear@5 234 glTranslatef(i & 1 ? 5 : -5, 1, i & 2 ? -5 : 5);
nuclear@5 235 draw_box(0.5, 2, 0.5, 1.0);
nuclear@5 236 glPopMatrix();
nuclear@5 237
nuclear@5 238 col[0] = i & 1 ? 1.0 : 0.3;
nuclear@5 239 col[1] = i == 0 ? 1.0 : 0.3;
nuclear@5 240 col[2] = i & 2 ? 1.0 : 0.3;
nuclear@5 241 glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, col);
nuclear@5 242
nuclear@5 243 glPushMatrix();
nuclear@5 244 if(i & 1) {
nuclear@5 245 glTranslatef(0, 0.25, i & 2 ? 2 : -2);
nuclear@5 246 } else {
nuclear@5 247 glTranslatef(i & 2 ? 2 : -2, 0.25, 0);
nuclear@5 248 }
nuclear@5 249 draw_box(0.5, 0.5, 0.5, 1.0);
nuclear@5 250 glPopMatrix();
nuclear@5 251 }
nuclear@5 252 }
nuclear@5 253
nuclear@5 254 void draw_box(float xsz, float ysz, float zsz, float norm_sign)
nuclear@5 255 {
nuclear@5 256 glMatrixMode(GL_MODELVIEW);
nuclear@5 257 glScalef(xsz * 0.5, ysz * 0.5, zsz * 0.5);
nuclear@5 258
nuclear@5 259 if(norm_sign < 0.0) {
nuclear@5 260 glFrontFace(GL_CW);
nuclear@5 261 }
nuclear@5 262
nuclear@5 263 glBegin(GL_QUADS);
nuclear@5 264 glNormal3f(0, 0, 1 * norm_sign);
nuclear@5 265 glTexCoord2f(0, 0); glVertex3f(-1, -1, 1);
nuclear@5 266 glTexCoord2f(1, 0); glVertex3f(1, -1, 1);
nuclear@5 267 glTexCoord2f(1, 1); glVertex3f(1, 1, 1);
nuclear@5 268 glTexCoord2f(0, 1); glVertex3f(-1, 1, 1);
nuclear@5 269 glNormal3f(1 * norm_sign, 0, 0);
nuclear@5 270 glTexCoord2f(0, 0); glVertex3f(1, -1, 1);
nuclear@5 271 glTexCoord2f(1, 0); glVertex3f(1, -1, -1);
nuclear@5 272 glTexCoord2f(1, 1); glVertex3f(1, 1, -1);
nuclear@5 273 glTexCoord2f(0, 1); glVertex3f(1, 1, 1);
nuclear@5 274 glNormal3f(0, 0, -1 * norm_sign);
nuclear@5 275 glTexCoord2f(0, 0); glVertex3f(1, -1, -1);
nuclear@5 276 glTexCoord2f(1, 0); glVertex3f(-1, -1, -1);
nuclear@5 277 glTexCoord2f(1, 1); glVertex3f(-1, 1, -1);
nuclear@5 278 glTexCoord2f(0, 1); glVertex3f(1, 1, -1);
nuclear@5 279 glNormal3f(-1 * norm_sign, 0, 0);
nuclear@5 280 glTexCoord2f(0, 0); glVertex3f(-1, -1, -1);
nuclear@5 281 glTexCoord2f(1, 0); glVertex3f(-1, -1, 1);
nuclear@5 282 glTexCoord2f(1, 1); glVertex3f(-1, 1, 1);
nuclear@5 283 glTexCoord2f(0, 1); glVertex3f(-1, 1, -1);
nuclear@5 284 glEnd();
nuclear@5 285 glBegin(GL_TRIANGLE_FAN);
nuclear@5 286 glNormal3f(0, 1 * norm_sign, 0);
nuclear@5 287 glTexCoord2f(0.5, 0.5); glVertex3f(0, 1, 0);
nuclear@5 288 glTexCoord2f(0, 0); glVertex3f(-1, 1, 1);
nuclear@5 289 glTexCoord2f(1, 0); glVertex3f(1, 1, 1);
nuclear@5 290 glTexCoord2f(1, 1); glVertex3f(1, 1, -1);
nuclear@5 291 glTexCoord2f(0, 1); glVertex3f(-1, 1, -1);
nuclear@5 292 glTexCoord2f(0, 0); glVertex3f(-1, 1, 1);
nuclear@5 293 glEnd();
nuclear@5 294 glBegin(GL_TRIANGLE_FAN);
nuclear@5 295 glNormal3f(0, -1 * norm_sign, 0);
nuclear@5 296 glTexCoord2f(0.5, 0.5); glVertex3f(0, -1, 0);
nuclear@5 297 glTexCoord2f(0, 0); glVertex3f(-1, -1, -1);
nuclear@5 298 glTexCoord2f(1, 0); glVertex3f(1, -1, -1);
nuclear@5 299 glTexCoord2f(1, 1); glVertex3f(1, -1, 1);
nuclear@5 300 glTexCoord2f(0, 1); glVertex3f(-1, -1, 1);
nuclear@5 301 glTexCoord2f(0, 0); glVertex3f(-1, -1, -1);
nuclear@5 302 glEnd();
nuclear@5 303
nuclear@5 304 glFrontFace(GL_CCW);
nuclear@5 305 }
nuclear@5 306
nuclear@5 307 /* update_rtarg creates (and/or resizes) the render target used to draw the two stero views */
nuclear@5 308 void update_rtarg(int width, int height)
nuclear@5 309 {
nuclear@5 310 if(!fbo) {
nuclear@5 311 /* if fbo does not exist, then nothing does... create every opengl object */
nuclear@5 312 glGenFramebuffers(1, &fbo);
nuclear@5 313 glGenTextures(1, &fb_tex);
nuclear@5 314 glGenRenderbuffers(1, &fb_depth);
nuclear@5 315
nuclear@5 316 glBindTexture(GL_TEXTURE_2D, fb_tex);
nuclear@5 317 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
nuclear@5 318 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
nuclear@5 319 }
nuclear@5 320
nuclear@5 321 glBindFramebuffer(GL_FRAMEBUFFER, fbo);
nuclear@5 322
nuclear@5 323 /* calculate the next power of two in both dimensions and use that as a texture size */
nuclear@5 324 fb_tex_width = next_pow2(width);
nuclear@5 325 fb_tex_height = next_pow2(height);
nuclear@5 326
nuclear@5 327 /* create and attach the texture that will be used as a color buffer */
nuclear@5 328 glBindTexture(GL_TEXTURE_2D, fb_tex);
nuclear@5 329 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, fb_tex_width, fb_tex_height, 0,
nuclear@5 330 GL_RGBA, GL_UNSIGNED_BYTE, 0);
nuclear@5 331 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, fb_tex, 0);
nuclear@5 332
nuclear@5 333 /* create and attach the renderbuffer that will serve as our z-buffer */
nuclear@5 334 glBindRenderbuffer(GL_RENDERBUFFER, fb_depth);
nuclear@5 335 glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, fb_tex_width, fb_tex_height);
nuclear@5 336 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, fb_depth);
nuclear@5 337
nuclear@5 338 if(glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
nuclear@5 339 fprintf(stderr, "incomplete framebuffer!\n");
nuclear@5 340 }
nuclear@5 341
nuclear@5 342 glBindFramebuffer(GL_FRAMEBUFFER, 0);
nuclear@5 343 printf("created render target: %dx%d (texture size: %dx%d)\n", width, height, fb_tex_width, fb_tex_height);
nuclear@5 344 }
nuclear@5 345
nuclear@5 346 int handle_event(SDL_Event *ev)
nuclear@5 347 {
nuclear@5 348 switch(ev->type) {
nuclear@5 349 case SDL_QUIT:
nuclear@5 350 return -1;
nuclear@5 351
nuclear@5 352 case SDL_KEYDOWN:
nuclear@5 353 case SDL_KEYUP:
nuclear@5 354 if(key_event(ev->key.keysym.sym, ev->key.state == SDL_PRESSED) == -1) {
nuclear@5 355 return -1;
nuclear@5 356 }
nuclear@5 357 break;
nuclear@5 358
nuclear@5 359 default:
nuclear@5 360 break;
nuclear@5 361 }
nuclear@5 362
nuclear@5 363 return 0;
nuclear@5 364 }
nuclear@5 365
nuclear@5 366 int key_event(int key, int state)
nuclear@5 367 {
nuclear@5 368 if(state) {
nuclear@5 369 switch(key) {
nuclear@5 370 case 27:
nuclear@5 371 return -1;
nuclear@5 372
nuclear@5 373 case ' ':
nuclear@5 374 /* allow the user to recenter by pressing space */
nuclear@5 375 vr_recenter();
nuclear@5 376 break;
nuclear@5 377
nuclear@5 378 case 'f':
nuclear@5 379 /* press f to move the window to the HMD */
nuclear@5 380 toggle_hmd_fullscreen();
nuclear@5 381 break;
nuclear@5 382
nuclear@5 383 default:
nuclear@5 384 break;
nuclear@5 385 }
nuclear@5 386 }
nuclear@5 387 return 0;
nuclear@5 388 }
nuclear@5 389
nuclear@5 390 unsigned int next_pow2(unsigned int x)
nuclear@5 391 {
nuclear@5 392 x -= 1;
nuclear@5 393 x |= x >> 1;
nuclear@5 394 x |= x >> 2;
nuclear@5 395 x |= x >> 4;
nuclear@5 396 x |= x >> 8;
nuclear@5 397 x |= x >> 16;
nuclear@5 398 return x + 1;
nuclear@5 399 }
nuclear@5 400
nuclear@5 401 /* convert a quaternion to a rotation matrix */
nuclear@5 402 void quat_to_matrix(const float *quat, float *mat)
nuclear@5 403 {
nuclear@5 404 mat[0] = 1.0 - 2.0 * quat[1] * quat[1] - 2.0 * quat[2] * quat[2];
nuclear@5 405 mat[4] = 2.0 * quat[0] * quat[1] + 2.0 * quat[3] * quat[2];
nuclear@5 406 mat[8] = 2.0 * quat[2] * quat[0] - 2.0 * quat[3] * quat[1];
nuclear@5 407 mat[12] = 0.0f;
nuclear@5 408
nuclear@5 409 mat[1] = 2.0 * quat[0] * quat[1] - 2.0 * quat[3] * quat[2];
nuclear@5 410 mat[5] = 1.0 - 2.0 * quat[0]*quat[0] - 2.0 * quat[2]*quat[2];
nuclear@5 411 mat[9] = 2.0 * quat[1] * quat[2] + 2.0 * quat[3] * quat[0];
nuclear@5 412 mat[13] = 0.0f;
nuclear@5 413
nuclear@5 414 mat[2] = 2.0 * quat[2] * quat[0] + 2.0 * quat[3] * quat[1];
nuclear@5 415 mat[6] = 2.0 * quat[1] * quat[2] - 2.0 * quat[3] * quat[0];
nuclear@5 416 mat[10] = 1.0 - 2.0 * quat[0]*quat[0] - 2.0 * quat[1]*quat[1];
nuclear@5 417 mat[14] = 0.0f;
nuclear@5 418
nuclear@5 419 mat[3] = mat[7] = mat[11] = 0.0f;
nuclear@5 420 mat[15] = 1.0f;
nuclear@5 421 }
nuclear@5 422
nuclear@5 423 /* generate a chessboard texture with tiles colored (r0, g0, b0) and (r1, g1, b1) */
nuclear@5 424 unsigned int gen_chess_tex(float r0, float g0, float b0, float r1, float g1, float b1)
nuclear@5 425 {
nuclear@5 426 int i, j;
nuclear@5 427 unsigned int tex;
nuclear@5 428 unsigned char img[8 * 8 * 3];
nuclear@5 429 unsigned char *pix = img;
nuclear@5 430
nuclear@5 431 for(i=0; i<8; i++) {
nuclear@5 432 for(j=0; j<8; j++) {
nuclear@5 433 int black = (i & 1) == (j & 1);
nuclear@5 434 pix[0] = (black ? r0 : r1) * 255;
nuclear@5 435 pix[1] = (black ? g0 : g1) * 255;
nuclear@5 436 pix[2] = (black ? b0 : b1) * 255;
nuclear@5 437 pix += 3;
nuclear@5 438 }
nuclear@5 439 }
nuclear@5 440
nuclear@5 441 glGenTextures(1, &tex);
nuclear@5 442 glBindTexture(GL_TEXTURE_2D, tex);
nuclear@5 443 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
nuclear@5 444 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
nuclear@5 445 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 8, 8, 0, GL_RGB, GL_UNSIGNED_BYTE, img);
nuclear@5 446
nuclear@5 447 return tex;
nuclear@5 448 }