libgoatvr

annotate example/src/main.c @ 30:1a8343ea54ce

fixed on windows
author John Tsiombikas <nuclear@member.fsf.org>
date Sat, 11 Apr 2015 04:01:47 +0300
parents 5136dfcea7b1
children
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@30 60 if(vr_init() == -1) {
nuclear@30 61 return -1;
nuclear@30 62 }
nuclear@30 63
nuclear@5 64 SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER);
nuclear@5 65
nuclear@5 66 x = y = SDL_WINDOWPOS_UNDEFINED;
nuclear@5 67 flags = SDL_WINDOW_OPENGL;
nuclear@5 68 if(!(win = SDL_CreateWindow("press 'f' to move to the HMD", x, y, 1280, 800, flags))) {
nuclear@5 69 fprintf(stderr, "failed to create window\n");
nuclear@5 70 return -1;
nuclear@5 71 }
nuclear@5 72 if(!(ctx = SDL_GL_CreateContext(win))) {
nuclear@5 73 fprintf(stderr, "failed to create OpenGL context\n");
nuclear@5 74 return -1;
nuclear@5 75 }
nuclear@5 76
nuclear@5 77 glewInit();
nuclear@5 78
nuclear@5 79 /* resize our window to match the HMD resolution */
nuclear@11 80 win_width = vr_geti(VR_DISPLAY_WIDTH);
nuclear@11 81 win_height = vr_geti(VR_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@11 90 fb_width = vr_geti(VR_LEYE_XRES) + vr_geti(VR_REYE_XRES);
nuclear@11 91 fb_height = vr_geti(VR_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@11 130 SDL_SetWindowPosition(win, vr_geti(VR_WIN_XOFFS), vr_geti(VR_WIN_YOFFS));
nuclear@5 131 SDL_SetWindowFullscreen(win, SDL_WINDOW_FULLSCREEN_DESKTOP);
nuclear@28 132 SDL_SetRelativeMouseMode(1);
nuclear@5 133 } else {
nuclear@5 134 /* return to windowed mode and move the window back to its original position */
nuclear@5 135 SDL_SetWindowFullscreen(win, 0);
nuclear@5 136 SDL_SetWindowPosition(win, prev_x, prev_y);
nuclear@28 137 SDL_SetRelativeMouseMode(0);
nuclear@5 138 }
nuclear@5 139 }
nuclear@5 140
nuclear@5 141 void display(void)
nuclear@5 142 {
nuclear@5 143 int i;
nuclear@8 144 float proj_mat[16] = {1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1};
nuclear@8 145 float view_mat[16] = {1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1};
nuclear@5 146
nuclear@5 147 /* start drawing onto our texture render target */
nuclear@5 148 glBindFramebuffer(GL_FRAMEBUFFER, fbo);
nuclear@5 149 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
nuclear@5 150
nuclear@5 151 /* for each eye ... */
nuclear@5 152 for(i=0; i<2; i++) {
nuclear@5 153 vr_begin(i);
nuclear@5 154
nuclear@5 155 /* -- viewport transformation --
nuclear@5 156 * setup the viewport to draw in the left half of the framebuffer when we're
nuclear@5 157 * rendering the left eye's view (0, 0, width/2, height), and in the right half
nuclear@5 158 * of the framebuffer for the right eye's view (width/2, 0, width/2, height)
nuclear@5 159 */
nuclear@19 160 glViewport(i == VR_EYE_LEFT ? 0 : fb_width / 2, 0, fb_width / 2, fb_height);
nuclear@5 161
nuclear@5 162 glMatrixMode(GL_PROJECTION);
nuclear@5 163 /* -- projection transformation --
nuclear@5 164 * we'll just have to use the projection matrix supplied by the oculus SDK for this eye
nuclear@5 165 * note that libovr matrices are the transpose of what OpenGL expects, so we have to
nuclear@5 166 * use glLoadTransposeMatrixf instead of glLoadMatrixf to load it.
nuclear@5 167 */
nuclear@5 168 if(vr_proj_matrix(i, 0.5, 500.0, proj_mat)) {
nuclear@8 169 glLoadMatrixf(proj_mat);
nuclear@5 170 } else {
nuclear@5 171 glLoadIdentity();
nuclear@5 172 gluPerspective(50.0, (float)fb_width / 2.0 / (float)fb_height, 0.5, 500.0);
nuclear@5 173 }
nuclear@5 174
nuclear@5 175 /* -- view/camera transformation --
nuclear@5 176 * we need to construct a view matrix by combining all the information provided by the oculus
nuclear@5 177 * SDK, about the position and orientation of the user's head in the world.
nuclear@5 178 */
nuclear@5 179 glMatrixMode(GL_MODELVIEW);
nuclear@5 180 vr_view_matrix(i, view_mat);
nuclear@8 181 glLoadMatrixf(view_mat);
nuclear@5 182 /* move the camera to the eye level of the user */
nuclear@11 183 glTranslatef(0, -vr_getf(VR_EYE_HEIGHT), 0);
nuclear@5 184
nuclear@5 185 /* finally draw the scene for this eye */
nuclear@5 186 draw_scene();
nuclear@5 187
nuclear@5 188 vr_end();
nuclear@5 189 }
nuclear@5 190
nuclear@5 191 /* after drawing both eyes into the texture render target, revert to drawing directly to the
nuclear@5 192 * display, and we call ovrHmd_EndFrame, to let the Oculus SDK draw both images properly
nuclear@5 193 * compensated for lens distortion and chromatic abberation onto the HMD screen.
nuclear@5 194 */
nuclear@5 195 glBindFramebuffer(GL_FRAMEBUFFER, 0);
nuclear@5 196 glViewport(0, 0, win_width, win_height);
nuclear@5 197
nuclear@5 198 vr_swap_buffers();
nuclear@5 199
nuclear@5 200 assert(glGetError() == GL_NO_ERROR);
nuclear@5 201 }
nuclear@5 202
nuclear@5 203 void draw_scene(void)
nuclear@5 204 {
nuclear@5 205 int i;
nuclear@5 206 float grey[] = {0.8, 0.8, 0.8, 1};
nuclear@5 207 float col[] = {0, 0, 0, 1};
nuclear@5 208 float lpos[][4] = {
nuclear@5 209 {-8, 2, 10, 1},
nuclear@5 210 {0, 15, 0, 1}
nuclear@5 211 };
nuclear@5 212 float lcol[][4] = {
nuclear@5 213 {0.8, 0.8, 0.8, 1},
nuclear@5 214 {0.4, 0.3, 0.3, 1}
nuclear@5 215 };
nuclear@5 216
nuclear@5 217 for(i=0; i<2; i++) {
nuclear@5 218 glLightfv(GL_LIGHT0 + i, GL_POSITION, lpos[i]);
nuclear@5 219 glLightfv(GL_LIGHT0 + i, GL_DIFFUSE, lcol[i]);
nuclear@5 220 }
nuclear@5 221
nuclear@5 222 glMatrixMode(GL_MODELVIEW);
nuclear@5 223
nuclear@5 224 glPushMatrix();
nuclear@5 225 glTranslatef(0, 10, 0);
nuclear@5 226 glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, grey);
nuclear@5 227 glBindTexture(GL_TEXTURE_2D, chess_tex);
nuclear@5 228 glEnable(GL_TEXTURE_2D);
nuclear@5 229 draw_box(30, 20, 30, -1.0);
nuclear@5 230 glDisable(GL_TEXTURE_2D);
nuclear@5 231 glPopMatrix();
nuclear@5 232
nuclear@5 233 for(i=0; i<4; i++) {
nuclear@5 234 glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, grey);
nuclear@5 235 glPushMatrix();
nuclear@5 236 glTranslatef(i & 1 ? 5 : -5, 1, i & 2 ? -5 : 5);
nuclear@5 237 draw_box(0.5, 2, 0.5, 1.0);
nuclear@5 238 glPopMatrix();
nuclear@5 239
nuclear@5 240 col[0] = i & 1 ? 1.0 : 0.3;
nuclear@5 241 col[1] = i == 0 ? 1.0 : 0.3;
nuclear@5 242 col[2] = i & 2 ? 1.0 : 0.3;
nuclear@5 243 glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, col);
nuclear@5 244
nuclear@5 245 glPushMatrix();
nuclear@5 246 if(i & 1) {
nuclear@5 247 glTranslatef(0, 0.25, i & 2 ? 2 : -2);
nuclear@5 248 } else {
nuclear@5 249 glTranslatef(i & 2 ? 2 : -2, 0.25, 0);
nuclear@5 250 }
nuclear@5 251 draw_box(0.5, 0.5, 0.5, 1.0);
nuclear@5 252 glPopMatrix();
nuclear@5 253 }
nuclear@19 254
nuclear@19 255 col[0] = 1;
nuclear@19 256 col[1] = 1;
nuclear@19 257 col[2] = 0.4;
nuclear@19 258 glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, col);
nuclear@19 259 draw_box(0.05, 1.2, 6, 1.0);
nuclear@19 260 draw_box(6, 1.2, 0.05, 1.0);
nuclear@5 261 }
nuclear@5 262
nuclear@5 263 void draw_box(float xsz, float ysz, float zsz, float norm_sign)
nuclear@5 264 {
nuclear@5 265 glMatrixMode(GL_MODELVIEW);
nuclear@19 266 glPushMatrix();
nuclear@5 267 glScalef(xsz * 0.5, ysz * 0.5, zsz * 0.5);
nuclear@5 268
nuclear@5 269 if(norm_sign < 0.0) {
nuclear@5 270 glFrontFace(GL_CW);
nuclear@5 271 }
nuclear@5 272
nuclear@5 273 glBegin(GL_QUADS);
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 glNormal3f(0, 0, -1 * norm_sign);
nuclear@5 285 glTexCoord2f(0, 0); glVertex3f(1, -1, -1);
nuclear@5 286 glTexCoord2f(1, 0); glVertex3f(-1, -1, -1);
nuclear@5 287 glTexCoord2f(1, 1); glVertex3f(-1, 1, -1);
nuclear@5 288 glTexCoord2f(0, 1); glVertex3f(1, 1, -1);
nuclear@5 289 glNormal3f(-1 * norm_sign, 0, 0);
nuclear@5 290 glTexCoord2f(0, 0); glVertex3f(-1, -1, -1);
nuclear@5 291 glTexCoord2f(1, 0); glVertex3f(-1, -1, 1);
nuclear@5 292 glTexCoord2f(1, 1); glVertex3f(-1, 1, 1);
nuclear@5 293 glTexCoord2f(0, 1); glVertex3f(-1, 1, -1);
nuclear@5 294 glEnd();
nuclear@5 295 glBegin(GL_TRIANGLE_FAN);
nuclear@5 296 glNormal3f(0, 1 * norm_sign, 0);
nuclear@5 297 glTexCoord2f(0.5, 0.5); glVertex3f(0, 1, 0);
nuclear@5 298 glTexCoord2f(0, 0); glVertex3f(-1, 1, 1);
nuclear@5 299 glTexCoord2f(1, 0); glVertex3f(1, 1, 1);
nuclear@5 300 glTexCoord2f(1, 1); glVertex3f(1, 1, -1);
nuclear@5 301 glTexCoord2f(0, 1); glVertex3f(-1, 1, -1);
nuclear@5 302 glTexCoord2f(0, 0); glVertex3f(-1, 1, 1);
nuclear@5 303 glEnd();
nuclear@5 304 glBegin(GL_TRIANGLE_FAN);
nuclear@5 305 glNormal3f(0, -1 * norm_sign, 0);
nuclear@5 306 glTexCoord2f(0.5, 0.5); glVertex3f(0, -1, 0);
nuclear@5 307 glTexCoord2f(0, 0); glVertex3f(-1, -1, -1);
nuclear@5 308 glTexCoord2f(1, 0); glVertex3f(1, -1, -1);
nuclear@5 309 glTexCoord2f(1, 1); glVertex3f(1, -1, 1);
nuclear@5 310 glTexCoord2f(0, 1); glVertex3f(-1, -1, 1);
nuclear@5 311 glTexCoord2f(0, 0); glVertex3f(-1, -1, -1);
nuclear@5 312 glEnd();
nuclear@5 313
nuclear@5 314 glFrontFace(GL_CCW);
nuclear@19 315 glPopMatrix();
nuclear@5 316 }
nuclear@5 317
nuclear@5 318 /* update_rtarg creates (and/or resizes) the render target used to draw the two stero views */
nuclear@5 319 void update_rtarg(int width, int height)
nuclear@5 320 {
nuclear@5 321 if(!fbo) {
nuclear@5 322 /* if fbo does not exist, then nothing does... create every opengl object */
nuclear@5 323 glGenFramebuffers(1, &fbo);
nuclear@5 324 glGenTextures(1, &fb_tex);
nuclear@5 325 glGenRenderbuffers(1, &fb_depth);
nuclear@5 326
nuclear@5 327 glBindTexture(GL_TEXTURE_2D, fb_tex);
nuclear@5 328 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
nuclear@5 329 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
nuclear@5 330 }
nuclear@5 331
nuclear@5 332 glBindFramebuffer(GL_FRAMEBUFFER, fbo);
nuclear@5 333
nuclear@5 334 /* calculate the next power of two in both dimensions and use that as a texture size */
nuclear@5 335 fb_tex_width = next_pow2(width);
nuclear@5 336 fb_tex_height = next_pow2(height);
nuclear@5 337
nuclear@5 338 /* create and attach the texture that will be used as a color buffer */
nuclear@5 339 glBindTexture(GL_TEXTURE_2D, fb_tex);
nuclear@5 340 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, fb_tex_width, fb_tex_height, 0,
nuclear@5 341 GL_RGBA, GL_UNSIGNED_BYTE, 0);
nuclear@5 342 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, fb_tex, 0);
nuclear@5 343
nuclear@5 344 /* create and attach the renderbuffer that will serve as our z-buffer */
nuclear@5 345 glBindRenderbuffer(GL_RENDERBUFFER, fb_depth);
nuclear@5 346 glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, fb_tex_width, fb_tex_height);
nuclear@5 347 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, fb_depth);
nuclear@5 348
nuclear@5 349 if(glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
nuclear@5 350 fprintf(stderr, "incomplete framebuffer!\n");
nuclear@5 351 }
nuclear@5 352
nuclear@5 353 glBindFramebuffer(GL_FRAMEBUFFER, 0);
nuclear@5 354 printf("created render target: %dx%d (texture size: %dx%d)\n", width, height, fb_tex_width, fb_tex_height);
nuclear@5 355 }
nuclear@5 356
nuclear@5 357 int handle_event(SDL_Event *ev)
nuclear@5 358 {
nuclear@5 359 switch(ev->type) {
nuclear@5 360 case SDL_QUIT:
nuclear@5 361 return -1;
nuclear@5 362
nuclear@5 363 case SDL_KEYDOWN:
nuclear@5 364 case SDL_KEYUP:
nuclear@5 365 if(key_event(ev->key.keysym.sym, ev->key.state == SDL_PRESSED) == -1) {
nuclear@5 366 return -1;
nuclear@5 367 }
nuclear@5 368 break;
nuclear@5 369
nuclear@5 370 default:
nuclear@5 371 break;
nuclear@5 372 }
nuclear@5 373
nuclear@5 374 return 0;
nuclear@5 375 }
nuclear@5 376
nuclear@5 377 int key_event(int key, int state)
nuclear@5 378 {
nuclear@5 379 if(state) {
nuclear@5 380 switch(key) {
nuclear@5 381 case 27:
nuclear@5 382 return -1;
nuclear@5 383
nuclear@5 384 case ' ':
nuclear@5 385 /* allow the user to recenter by pressing space */
nuclear@5 386 vr_recenter();
nuclear@5 387 break;
nuclear@5 388
nuclear@5 389 case 'f':
nuclear@5 390 /* press f to move the window to the HMD */
nuclear@5 391 toggle_hmd_fullscreen();
nuclear@5 392 break;
nuclear@5 393
nuclear@5 394 default:
nuclear@5 395 break;
nuclear@5 396 }
nuclear@5 397 }
nuclear@5 398 return 0;
nuclear@5 399 }
nuclear@5 400
nuclear@5 401 unsigned int next_pow2(unsigned int x)
nuclear@5 402 {
nuclear@5 403 x -= 1;
nuclear@5 404 x |= x >> 1;
nuclear@5 405 x |= x >> 2;
nuclear@5 406 x |= x >> 4;
nuclear@5 407 x |= x >> 8;
nuclear@5 408 x |= x >> 16;
nuclear@5 409 return x + 1;
nuclear@5 410 }
nuclear@5 411
nuclear@5 412 /* convert a quaternion to a rotation matrix */
nuclear@5 413 void quat_to_matrix(const float *quat, float *mat)
nuclear@5 414 {
nuclear@5 415 mat[0] = 1.0 - 2.0 * quat[1] * quat[1] - 2.0 * quat[2] * quat[2];
nuclear@5 416 mat[4] = 2.0 * quat[0] * quat[1] + 2.0 * quat[3] * quat[2];
nuclear@5 417 mat[8] = 2.0 * quat[2] * quat[0] - 2.0 * quat[3] * quat[1];
nuclear@5 418 mat[12] = 0.0f;
nuclear@5 419
nuclear@5 420 mat[1] = 2.0 * quat[0] * quat[1] - 2.0 * quat[3] * quat[2];
nuclear@5 421 mat[5] = 1.0 - 2.0 * quat[0]*quat[0] - 2.0 * quat[2]*quat[2];
nuclear@5 422 mat[9] = 2.0 * quat[1] * quat[2] + 2.0 * quat[3] * quat[0];
nuclear@5 423 mat[13] = 0.0f;
nuclear@5 424
nuclear@5 425 mat[2] = 2.0 * quat[2] * quat[0] + 2.0 * quat[3] * quat[1];
nuclear@5 426 mat[6] = 2.0 * quat[1] * quat[2] - 2.0 * quat[3] * quat[0];
nuclear@5 427 mat[10] = 1.0 - 2.0 * quat[0]*quat[0] - 2.0 * quat[1]*quat[1];
nuclear@5 428 mat[14] = 0.0f;
nuclear@5 429
nuclear@5 430 mat[3] = mat[7] = mat[11] = 0.0f;
nuclear@5 431 mat[15] = 1.0f;
nuclear@5 432 }
nuclear@5 433
nuclear@5 434 /* generate a chessboard texture with tiles colored (r0, g0, b0) and (r1, g1, b1) */
nuclear@5 435 unsigned int gen_chess_tex(float r0, float g0, float b0, float r1, float g1, float b1)
nuclear@5 436 {
nuclear@5 437 int i, j;
nuclear@5 438 unsigned int tex;
nuclear@5 439 unsigned char img[8 * 8 * 3];
nuclear@5 440 unsigned char *pix = img;
nuclear@5 441
nuclear@5 442 for(i=0; i<8; i++) {
nuclear@5 443 for(j=0; j<8; j++) {
nuclear@5 444 int black = (i & 1) == (j & 1);
nuclear@5 445 pix[0] = (black ? r0 : r1) * 255;
nuclear@5 446 pix[1] = (black ? g0 : g1) * 255;
nuclear@5 447 pix[2] = (black ? b0 : b1) * 255;
nuclear@5 448 pix += 3;
nuclear@5 449 }
nuclear@5 450 }
nuclear@5 451
nuclear@5 452 glGenTextures(1, &tex);
nuclear@5 453 glBindTexture(GL_TEXTURE_2D, tex);
nuclear@5 454 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
nuclear@5 455 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
nuclear@5 456 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 8, 8, 0, GL_RGB, GL_UNSIGNED_BYTE, img);
nuclear@5 457
nuclear@5 458 return tex;
nuclear@5 459 }