clray

annotate src/clray.cc @ 56:e3b4457dc4d2

added glFinish after swap-buffers to make the program absolutely correct in regards to mediating usage of the shared GL/CL texture image
author John Tsiombikas <nuclear@member.fsf.org>
date Mon, 06 Sep 2010 05:40:47 +0100
parents 55b30d8b6805
children 14c8ebe8f122
rev   line source
nuclear@0 1 #include <stdio.h>
nuclear@3 2 #include <stdlib.h>
nuclear@2 3 #include <string.h>
nuclear@27 4 #include <ctype.h>
nuclear@2 5 #include <errno.h>
nuclear@3 6 #ifndef __APPLE__
nuclear@3 7 #include <GL/glut.h>
nuclear@3 8 #else
nuclear@3 9 #include <GLUT/glut.h>
nuclear@3 10 #endif
nuclear@3 11 #include "rt.h"
nuclear@12 12 #include "matrix.h"
nuclear@22 13 #include "scene.h"
nuclear@39 14 #include "ocl.h"
John@49 15 #include "ogl.h"
John@49 16
John@49 17 #ifdef _MSC_VER
John@49 18 #define snprintf _snprintf
John@49 19 #endif
nuclear@0 20
nuclear@3 21 void cleanup();
nuclear@3 22 void disp();
nuclear@3 23 void reshape(int x, int y);
nuclear@3 24 void keyb(unsigned char key, int x, int y);
nuclear@3 25 void mouse(int bn, int status, int x, int y);
nuclear@3 26 void motion(int x, int y);
nuclear@47 27 bool capture(const char *namefmt);
nuclear@2 28 bool write_ppm(const char *fname, float *fb, int xsz, int ysz);
nuclear@2 29
nuclear@3 30 static int xsz, ysz;
nuclear@3 31 static bool need_update = true;
nuclear@3 32
nuclear@8 33 static float cam_theta, cam_phi = 25.0;
nuclear@8 34 static float cam_dist = 10.0;
nuclear@8 35
nuclear@32 36 static bool dbg_glrender = false;
nuclear@27 37 static bool dbg_show_kdtree = false;
nuclear@27 38 static bool dbg_show_obj = true;
John@50 39 bool dbg_frame_time = true;
nuclear@13 40
nuclear@13 41 static Scene scn;
nuclear@39 42 static unsigned int tex;
nuclear@12 43
nuclear@3 44 int main(int argc, char **argv)
nuclear@0 45 {
nuclear@3 46 glutInitWindowSize(800, 600);
nuclear@3 47 glutInit(&argc, argv);
nuclear@13 48
nuclear@13 49 int loaded = 0;
nuclear@13 50 for(int i=1; i<argc; i++) {
nuclear@27 51 if(argv[i][0] == '-' && argv[i][2] == 0) {
nuclear@27 52 switch(argv[i][1]) {
nuclear@27 53 case 'i':
nuclear@27 54 if(!argv[++i] || !isdigit(argv[i][0])) {
nuclear@27 55 fprintf(stderr, "-i must be followed by the intersection cost\n");
nuclear@27 56 return 1;
nuclear@27 57 }
nuclear@27 58
nuclear@27 59 set_accel_param(ACCEL_PARAM_COST_INTERSECT, atoi(argv[i]));
nuclear@27 60 break;
nuclear@27 61
nuclear@27 62 case 't':
nuclear@27 63 if(!argv[++i] || !isdigit(argv[i][0])) {
nuclear@27 64 fprintf(stderr, "-t must be followed by the traversal cost\n");
nuclear@27 65 return 1;
nuclear@27 66 }
nuclear@27 67
nuclear@27 68 set_accel_param(ACCEL_PARAM_COST_TRAVERSE, atoi(argv[i]));
nuclear@27 69 break;
nuclear@27 70
nuclear@27 71 case 'c':
nuclear@27 72 if(!argv[++i] || !isdigit(argv[i][0])) {
nuclear@27 73 fprintf(stderr, "-c must be followed by the max number of items per leaf node\n");
nuclear@27 74 return 1;
nuclear@27 75 }
nuclear@27 76
nuclear@27 77 set_accel_param(ACCEL_PARAM_MAX_NODE_ITEMS, atoi(argv[i]));
nuclear@27 78 break;
nuclear@27 79
nuclear@46 80 case 'd':
nuclear@46 81 dbg_glrender = true;
nuclear@46 82 break;
nuclear@46 83
nuclear@27 84 default:
nuclear@27 85 fprintf(stderr, "unrecognized option: %s\n", argv[i]);
nuclear@27 86 return 1;
nuclear@27 87 }
nuclear@27 88 } else {
nuclear@27 89 if(!scn.load(argv[i])) {
nuclear@27 90 fprintf(stderr, "failed to load scene: %s\n", argv[i]);
nuclear@27 91 return false;
nuclear@27 92 }
nuclear@27 93 loaded++;
nuclear@13 94 }
nuclear@13 95 }
nuclear@13 96
nuclear@13 97 if(!loaded) {
nuclear@13 98 fprintf(stderr, "you must specify a scene file to load\n");
nuclear@13 99 return false;
nuclear@13 100 }
nuclear@13 101 if(!scn.get_num_faces()) {
nuclear@13 102 fprintf(stderr, "didn't load any polygons\n");
nuclear@13 103 return false;
nuclear@13 104 }
nuclear@13 105
nuclear@18 106 glutInitDisplayMode(GLUT_RGB | GLUT_DEPTH | GLUT_DOUBLE);
nuclear@3 107 glutCreateWindow("OpenCL Raytracer");
nuclear@0 108
nuclear@3 109 xsz = glutGet(GLUT_WINDOW_WIDTH);
nuclear@3 110 ysz = glutGet(GLUT_WINDOW_HEIGHT);
nuclear@2 111
nuclear@3 112 glutDisplayFunc(disp);
nuclear@3 113 glutReshapeFunc(reshape);
nuclear@3 114 glutKeyboardFunc(keyb);
nuclear@3 115 glutMouseFunc(mouse);
nuclear@3 116 glutMotionFunc(motion);
nuclear@0 117
nuclear@32 118 unsigned int *test_pattern = new unsigned int[xsz * ysz];
nuclear@32 119 for(int i=0; i<ysz; i++) {
nuclear@32 120 for(int j=0; j<xsz; j++) {
nuclear@32 121 test_pattern[i * xsz + j] = ((i >> 4) & 1) == ((j >> 4) & 1) ? 0xff0000 : 0xff00;
nuclear@32 122 }
nuclear@32 123 }
nuclear@27 124
nuclear@39 125 glGenTextures(1, &tex);
nuclear@39 126 glBindTexture(GL_TEXTURE_2D, tex);
nuclear@3 127 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
nuclear@3 128 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
nuclear@3 129 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
nuclear@3 130 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
nuclear@39 131 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F_ARB, xsz, ysz, 0, GL_RGBA, GL_UNSIGNED_BYTE, test_pattern);
nuclear@32 132 delete [] test_pattern;
nuclear@2 133
nuclear@39 134 if(!init_opencl()) {
nuclear@39 135 return 1;
nuclear@39 136 }
nuclear@39 137
nuclear@39 138 if(!init_renderer(xsz, ysz, &scn, tex)) {
nuclear@39 139 return 1;
nuclear@39 140 }
nuclear@39 141 atexit(cleanup);
nuclear@39 142
nuclear@3 143 glutMainLoop();
nuclear@0 144 return 0;
nuclear@0 145 }
nuclear@2 146
nuclear@3 147 void cleanup()
nuclear@2 148 {
nuclear@41 149 printf("destroying renderer ...\n");
nuclear@3 150 destroy_renderer();
nuclear@40 151
nuclear@41 152 printf("shutting down OpenCL ...\n");
nuclear@40 153 destroy_opencl();
nuclear@40 154
nuclear@41 155 printf("cleaning up OpenGL resources ...\n");
nuclear@41 156 glDeleteTextures(1, &tex);
nuclear@3 157 }
nuclear@2 158
nuclear@12 159 static Matrix4x4 mat, inv_mat, inv_trans;
nuclear@12 160
nuclear@3 161 void disp()
nuclear@3 162 {
nuclear@8 163 glMatrixMode(GL_MODELVIEW);
nuclear@8 164 glLoadIdentity();
nuclear@8 165
nuclear@3 166 if(need_update) {
nuclear@12 167 glPushMatrix();
nuclear@12 168 glRotatef(-cam_theta, 0, 1, 0);
nuclear@12 169 glRotatef(-cam_phi, 1, 0, 0);
nuclear@12 170 glTranslatef(0, 0, cam_dist);
nuclear@8 171
nuclear@12 172 glGetFloatv(GL_MODELVIEW_MATRIX, mat.m);
nuclear@8 173
nuclear@12 174 inv_mat = mat;
nuclear@12 175 inv_mat.invert();
nuclear@12 176
nuclear@12 177 /*inv_trans = inv_mat;
nuclear@12 178 inv_trans.transpose();*/
nuclear@12 179 inv_trans = mat;
nuclear@12 180 inv_trans.m[3] = inv_trans.m[7] = inv_trans.m[11] = 0.0;
nuclear@12 181 inv_trans.m[12] = inv_trans.m[13] = inv_trans.m[14] = 0.0;
nuclear@12 182 inv_trans.m[15] = 1.0;
nuclear@12 183
nuclear@12 184 set_xform(mat.m, inv_trans.m);
nuclear@8 185 glPopMatrix();
nuclear@8 186
nuclear@13 187 if(!dbg_glrender) {
nuclear@13 188 if(!render()) {
nuclear@13 189 exit(1);
nuclear@13 190 }
nuclear@13 191 need_update = false;
nuclear@12 192 }
nuclear@3 193 }
nuclear@2 194
nuclear@12 195 if(dbg_glrender) {
nuclear@12 196 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
nuclear@12 197 glLoadMatrixf(inv_mat.m);
nuclear@27 198 dbg_render_gl(&scn, dbg_show_kdtree, dbg_show_obj);
nuclear@12 199 } else {
nuclear@12 200 glEnable(GL_TEXTURE_2D);
nuclear@22 201 glDisable(GL_LIGHTING);
nuclear@2 202
nuclear@12 203 glBegin(GL_QUADS);
nuclear@12 204 glColor3f(1, 1, 1);
nuclear@12 205 glTexCoord2f(0, 1); glVertex2f(-1, -1);
nuclear@12 206 glTexCoord2f(1, 1); glVertex2f(1, -1);
nuclear@12 207 glTexCoord2f(1, 0); glVertex2f(1, 1);
nuclear@12 208 glTexCoord2f(0, 0); glVertex2f(-1, 1);
nuclear@12 209 glEnd();
nuclear@2 210
nuclear@12 211 glDisable(GL_TEXTURE_2D);
nuclear@12 212 }
nuclear@3 213
nuclear@3 214 glutSwapBuffers();
nuclear@56 215
nuclear@56 216 /* We need to make sure OpenGL has finished with the texture
nuclear@56 217 * before allowing the OpenCL kernel to run again.
nuclear@56 218 */
nuclear@56 219 glFinish();
nuclear@3 220 }
nuclear@3 221
nuclear@3 222 void reshape(int x, int y)
nuclear@3 223 {
nuclear@3 224 glViewport(0, 0, x, y);
nuclear@3 225
nuclear@3 226 /* reallocate the framebuffer */
nuclear@3 227 /*delete [] fb;
nuclear@3 228 fb = new float[x * y * 4];
nuclear@3 229 set_framebuffer(fb, x, y);*/
nuclear@3 230 }
nuclear@3 231
nuclear@47 232 void idle()
nuclear@47 233 {
nuclear@47 234 need_update = true;
nuclear@47 235 glutPostRedisplay();
nuclear@47 236 }
nuclear@47 237
nuclear@3 238 void keyb(unsigned char key, int x, int y)
nuclear@3 239 {
nuclear@3 240 switch(key) {
nuclear@3 241 case 27:
nuclear@3 242 exit(0);
nuclear@3 243
nuclear@47 244 case '\b':
nuclear@47 245 {
nuclear@47 246 static bool busyloop;
nuclear@47 247
nuclear@47 248 busyloop = !busyloop;
nuclear@47 249 printf("%s busy-looping\n", busyloop ? "WARNING: enabling" : "disabling");
nuclear@47 250 glutIdleFunc(busyloop ? idle : 0);
nuclear@47 251 }
nuclear@3 252 break;
nuclear@3 253
nuclear@12 254 case 'd':
nuclear@12 255 dbg_glrender = !dbg_glrender;
nuclear@12 256 if(dbg_glrender) {
nuclear@21 257 printf("Debug OpenGL rendering\n");
nuclear@21 258 } else {
nuclear@21 259 printf("Raytracing\n");
nuclear@12 260 }
nuclear@3 261 glutPostRedisplay();
nuclear@3 262 break;
nuclear@3 263
nuclear@27 264 case 'k':
nuclear@27 265 dbg_show_kdtree = !dbg_show_kdtree;
nuclear@27 266 if(dbg_glrender) {
nuclear@27 267 glutPostRedisplay();
nuclear@27 268 }
nuclear@27 269 break;
nuclear@27 270
nuclear@27 271 case 'o':
nuclear@27 272 dbg_show_obj = !dbg_show_obj;
nuclear@27 273 if(dbg_glrender) {
nuclear@27 274 glutPostRedisplay();
nuclear@27 275 }
nuclear@27 276 break;
nuclear@27 277
nuclear@47 278 case 's':
nuclear@47 279 {
nuclear@47 280 bool shadows = get_render_option_bool(ROPT_SHAD);
nuclear@47 281 shadows = !shadows;
nuclear@47 282 printf("%s shadows\n", shadows ? "enabling" : "disabling");
nuclear@47 283 set_render_option(ROPT_SHAD, shadows);
nuclear@47 284 need_update = true;
nuclear@47 285 glutPostRedisplay();
nuclear@47 286 }
nuclear@47 287 break;
nuclear@47 288
nuclear@47 289 case 'r':
nuclear@47 290 {
nuclear@47 291 bool refl = get_render_option_bool(ROPT_REFL);
nuclear@47 292 refl = !refl;
nuclear@47 293 printf("%s reflections\n", refl ? "enabling" : "disabling");
nuclear@47 294 set_render_option(ROPT_REFL, refl);
nuclear@47 295 need_update = true;
nuclear@47 296 glutPostRedisplay();
nuclear@47 297 }
nuclear@47 298 break;
nuclear@47 299
nuclear@47 300 case ']':
nuclear@47 301 {
nuclear@47 302 int iter = get_render_option_int(ROPT_ITER);
nuclear@47 303 printf("setting max iterations: %d\n", iter + 1);
nuclear@47 304 set_render_option(ROPT_ITER, iter + 1);
nuclear@47 305 need_update = true;
nuclear@47 306 glutPostRedisplay();
nuclear@47 307 }
nuclear@47 308 break;
nuclear@47 309
nuclear@47 310 case '[':
nuclear@47 311 {
nuclear@47 312 int iter = get_render_option_int(ROPT_ITER);
nuclear@47 313 if(iter-- > 0) {
nuclear@47 314 printf("setting max iterations: %d\n", iter);
nuclear@47 315 set_render_option(ROPT_ITER, iter);
nuclear@47 316 need_update = true;
nuclear@47 317 glutPostRedisplay();
nuclear@47 318 }
nuclear@47 319 }
nuclear@47 320 break;
nuclear@47 321
nuclear@47 322 case '`':
nuclear@47 323 capture("shot%03d.ppm");
nuclear@47 324 break;
nuclear@47 325
John@50 326 case 't':
John@50 327 dbg_frame_time = !dbg_frame_time;
John@50 328 break;
John@50 329
nuclear@3 330 default:
nuclear@3 331 break;
nuclear@3 332 }
nuclear@3 333 }
nuclear@3 334
nuclear@8 335 static bool bnstate[32];
nuclear@8 336 static int prev_x, prev_y;
nuclear@8 337
nuclear@3 338 void mouse(int bn, int state, int x, int y)
nuclear@3 339 {
nuclear@8 340 if(state == GLUT_DOWN) {
nuclear@8 341 prev_x = x;
nuclear@8 342 prev_y = y;
nuclear@8 343 bnstate[bn] = true;
nuclear@8 344 } else {
nuclear@8 345 bnstate[bn] = false;
nuclear@8 346 }
nuclear@3 347 }
nuclear@3 348
nuclear@8 349 #define ROT_SCALE 0.5
nuclear@8 350 #define PAN_SCALE 0.1
nuclear@8 351
nuclear@3 352 void motion(int x, int y)
nuclear@3 353 {
nuclear@8 354 int dx = x - prev_x;
nuclear@8 355 int dy = y - prev_y;
nuclear@8 356 prev_x = x;
nuclear@8 357 prev_y = y;
nuclear@8 358
nuclear@8 359 if(bnstate[0]) {
nuclear@8 360 cam_theta += dx * ROT_SCALE;
nuclear@8 361 cam_phi += dy * ROT_SCALE;
nuclear@8 362
nuclear@12 363 if(cam_phi < -89) cam_phi = -89;
nuclear@8 364 if(cam_phi > 89) cam_phi = 89;
nuclear@8 365
nuclear@8 366 need_update = true;
nuclear@8 367 glutPostRedisplay();
nuclear@8 368 }
nuclear@8 369 if(bnstate[2]) {
nuclear@8 370 cam_dist += dy * PAN_SCALE;
nuclear@8 371 if(cam_dist < 0) cam_dist = 0;
nuclear@8 372
nuclear@8 373 need_update = true;
nuclear@8 374 glutPostRedisplay();
nuclear@8 375 }
nuclear@2 376 }
nuclear@2 377
nuclear@47 378 bool capture(const char *namefmt)
nuclear@47 379 {
nuclear@47 380 static int num;
nuclear@47 381 char fname[256];
nuclear@47 382
nuclear@47 383 num++;
nuclear@47 384 snprintf(fname, sizeof fname, namefmt, num);
nuclear@47 385 printf("saving image %s\n", fname);
nuclear@47 386
nuclear@47 387 float *pixels = new float[4 * xsz * ysz];
nuclear@47 388 glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_FLOAT, pixels);
nuclear@47 389
nuclear@52 390 bool res = write_ppm(fname, pixels, xsz, ysz);
nuclear@47 391 if(!res) {
nuclear@47 392 num--;
nuclear@47 393 }
nuclear@47 394 delete [] pixels;
nuclear@47 395 return res;
nuclear@47 396 }
nuclear@47 397
nuclear@2 398 bool write_ppm(const char *fname, float *fb, int xsz, int ysz)
nuclear@2 399 {
nuclear@2 400 FILE *fp;
nuclear@2 401
nuclear@2 402 if(!(fp = fopen(fname, "wb"))) {
nuclear@2 403 fprintf(stderr, "write_ppm: failed to open file %s for writing: %s\n", fname, strerror(errno));
nuclear@2 404 return false;
nuclear@2 405 }
nuclear@2 406 fprintf(fp, "P6\n%d %d\n255\n", xsz, ysz);
nuclear@2 407
nuclear@2 408 for(int i=0; i<xsz * ysz * 4; i++) {
nuclear@2 409 if(i % 4 == 3) continue;
nuclear@2 410
nuclear@2 411 unsigned char c = (unsigned char)(fb[i] * 255.0);
nuclear@2 412 fputc(c, fp);
nuclear@2 413 }
nuclear@2 414 fclose(fp);
nuclear@2 415 return true;
nuclear@2 416 }