clray

view src/clray.cc @ 47:30bf84881553

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