nuclear@0: #include nuclear@0: #include nuclear@8: #include nuclear@3: #include nuclear@0: #include nuclear@0: #include nuclear@0: #include nuclear@0: #include "sdr.h" nuclear@1: #include "gui.h" nuclear@3: #include "vmath.h" nuclear@0: nuclear@6: #define DEG_TO_RAD(x) (M_PI * (x) / 180.0) nuclear@6: nuclear@0: void disp(); nuclear@8: void render(); nuclear@0: void reshape(int x, int y); nuclear@0: void keyb(unsigned char key, int x, int y); nuclear@1: void keyb_up(unsigned char key, int x, int y); nuclear@0: void mouse(int bn, int state, int x, int y); nuclear@0: void motion(int x, int y); nuclear@1: void passive_motion(int x, int y); nuclear@6: void sball_motion(int x, int y, int z); nuclear@6: void sball_rot(int x, int y, int z); nuclear@6: void sball_button(int bn, int state); nuclear@6: nuclear@0: nuclear@0: int load_shader(); nuclear@0: unsigned int create_ray_texture(int xsz, int ysz, float vfov, Vector2 *tex_scale = 0); nuclear@0: static Vector3 get_primary_ray_dir(int x, int y, int w, int h, float vfov_deg); nuclear@0: static int round_pow2(int x); nuclear@0: nuclear@8: int parse_opt(int argc, char **argv); nuclear@8: nuclear@8: nuclear@0: float cam_theta = 0, cam_phi = 0, cam_dist = 4.0; nuclear@6: float cam_x, cam_y, cam_z; nuclear@0: nuclear@0: unsigned int sdr; nuclear@0: unsigned int ray_tex; nuclear@0: Vector2 tex_scale; nuclear@0: Vector4 seed; nuclear@0: float err_thres = 0.0075; nuclear@0: int iter = 10; nuclear@1: float reflectivity = 0.2; nuclear@5: Vector3 color(0.75, 0.75, 0.75); nuclear@0: nuclear@8: int use_stereo; nuclear@8: float eye_sep = 0.5; nuclear@8: nuclear@0: int main(int argc, char **argv) nuclear@0: { nuclear@0: int xsz, ysz; nuclear@0: nuclear@0: seed = Vector4(0.4, 0.0, 0.0, -0.8); nuclear@0: nuclear@0: glutInitWindowSize(640, 480); nuclear@0: glutInit(&argc, argv); nuclear@8: nuclear@8: if(parse_opt(argc, argv) == -1) { nuclear@8: return 1; nuclear@8: } nuclear@8: nuclear@8: glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE | (use_stereo ? GLUT_STEREO : 0)); nuclear@0: glutCreateWindow("Raytraced Fractals"); nuclear@0: xsz = glutGet(GLUT_WINDOW_WIDTH); nuclear@0: ysz = glutGet(GLUT_WINDOW_HEIGHT); nuclear@0: nuclear@0: glutDisplayFunc(disp); nuclear@0: glutReshapeFunc(reshape); nuclear@0: glutKeyboardFunc(keyb); nuclear@1: glutKeyboardUpFunc(keyb_up); nuclear@0: glutMouseFunc(mouse); nuclear@0: glutMotionFunc(motion); nuclear@1: glutPassiveMotionFunc(passive_motion); nuclear@6: glutSpaceballMotionFunc(sball_motion); nuclear@6: glutSpaceballRotateFunc(sball_rot); nuclear@6: glutSpaceballButtonFunc(sball_button); nuclear@0: nuclear@0: glewInit(); nuclear@0: nuclear@8: glEnable(GL_CULL_FACE); nuclear@8: nuclear@0: if(load_shader() == -1) { nuclear@0: return 1; nuclear@0: } nuclear@0: nuclear@1: if(gui_init(xsz, ysz) == -1) { nuclear@1: return 1; nuclear@1: } nuclear@1: nuclear@0: glutMainLoop(); nuclear@0: return 0; nuclear@0: } nuclear@0: nuclear@0: int load_shader() nuclear@0: { nuclear@0: if(sdr) { nuclear@0: free_program(sdr); nuclear@0: } nuclear@0: nuclear@0: if(!(sdr = create_program_load("sdr/sdr.v.glsl", "sdr/julia.p.glsl"))) { nuclear@0: return -1; nuclear@0: } nuclear@0: set_uniform_float4(sdr, "seed", seed.x, seed.y, seed.z, seed.w); nuclear@0: set_uniform_float(sdr, "err_thres", err_thres); nuclear@0: set_uniform_int(sdr, "iter", iter); nuclear@1: set_uniform_float(sdr, "reflectivity", reflectivity); nuclear@1: set_uniform_float3(sdr, "diffuse_color", color.x, color.y, color.z); nuclear@1: nuclear@0: return 0; nuclear@0: } nuclear@0: nuclear@0: void disp() nuclear@0: { nuclear@0: glMatrixMode(GL_MODELVIEW); nuclear@0: glLoadIdentity(); nuclear@6: glTranslatef(cam_x, cam_y, -cam_z); nuclear@0: glRotatef(cam_theta, 0, 1, 0); nuclear@0: glRotatef(cam_phi, 1, 0, 0); nuclear@0: glTranslatef(0, 0, -cam_dist); nuclear@0: nuclear@0: float lpos[] = {-1, 1, 3, 0}; nuclear@0: glLightfv(GL_LIGHT0, GL_POSITION, lpos); nuclear@0: nuclear@0: nuclear@4: set_uniform_float4(sdr, "seed", seed.x, seed.y, seed.z, seed.w); nuclear@4: set_uniform_float(sdr, "reflectivity", reflectivity); nuclear@4: set_uniform_int(sdr, "iter", iter); nuclear@4: set_uniform_float(sdr, "err_thres", err_thres); nuclear@5: set_uniform_float3(sdr, "diffuse_color", color.x, color.y, color.z); nuclear@4: nuclear@8: glBindTexture(GL_TEXTURE_2D, ray_tex); nuclear@8: nuclear@8: nuclear@8: if(use_stereo) { nuclear@8: glDrawBuffer(GL_BACK_LEFT); nuclear@8: set_uniform_float(sdr, "eye_offs", -eye_sep / 2.0); nuclear@8: } else { nuclear@8: set_uniform_float(sdr, "eye_offs", 0); nuclear@8: } nuclear@8: nuclear@8: render(); nuclear@8: nuclear@8: if(use_stereo) { nuclear@8: glDrawBuffer(GL_BACK_RIGHT); nuclear@8: nuclear@8: set_uniform_float(sdr, "eye_offs", eye_sep / 2.0); nuclear@8: render(); nuclear@8: } nuclear@8: nuclear@8: glutSwapBuffers(); nuclear@8: assert(glGetError() == GL_NO_ERROR); nuclear@8: } nuclear@8: nuclear@8: void render() nuclear@8: { nuclear@0: glMatrixMode(GL_TEXTURE); nuclear@0: glPushMatrix(); nuclear@0: glScalef(tex_scale.x, tex_scale.y, 1.0); nuclear@0: nuclear@0: glEnable(GL_TEXTURE_2D); nuclear@0: bind_program(sdr); nuclear@0: nuclear@0: glBegin(GL_QUADS); nuclear@0: glColor3f(1, 1, 1); nuclear@0: glTexCoord2f(0, 1); glVertex2f(-1, -1); nuclear@0: glTexCoord2f(1, 1); glVertex2f(1, -1); nuclear@0: glTexCoord2f(1, 0); glVertex2f(1, 1); nuclear@0: glTexCoord2f(0, 0); glVertex2f(-1, 1); nuclear@0: glEnd(); nuclear@0: nuclear@0: bind_program(0); nuclear@0: glDisable(GL_TEXTURE_2D); nuclear@0: nuclear@0: glMatrixMode(GL_TEXTURE); nuclear@0: glPopMatrix(); nuclear@0: nuclear@1: gui_draw(); nuclear@0: } nuclear@0: nuclear@0: void reshape(int x, int y) nuclear@0: { nuclear@0: glViewport(0, 0, x, y); nuclear@0: glMatrixMode(GL_PROJECTION); nuclear@0: glLoadIdentity(); nuclear@0: gluPerspective(45.0, (float)x / (float)y, 1.0, 1000.0); nuclear@0: nuclear@5: imtk_set_viewport(x, y); nuclear@5: nuclear@0: if(ray_tex) { nuclear@0: glDeleteTextures(1, &ray_tex); nuclear@0: } nuclear@0: ray_tex = create_ray_texture(x, y, 50.0, &tex_scale); nuclear@0: } nuclear@0: nuclear@0: nuclear@0: void keyb(unsigned char key, int x, int y) nuclear@0: { nuclear@0: switch(key) { nuclear@0: case 27: nuclear@0: exit(0); nuclear@0: nuclear@0: case '-': nuclear@0: if(iter > 1) { nuclear@0: iter--; nuclear@0: set_uniform_int(sdr, "iter", iter); nuclear@0: printf("iter: %d\n", iter); nuclear@0: glutPostRedisplay(); nuclear@0: } nuclear@0: break; nuclear@0: nuclear@0: case '=': nuclear@0: iter++; nuclear@0: set_uniform_int(sdr, "iter", iter); nuclear@0: printf("iter: %d\n", iter); nuclear@0: glutPostRedisplay(); nuclear@0: break; nuclear@0: nuclear@0: case ',': nuclear@0: err_thres -= 0.001; nuclear@0: set_uniform_float(sdr, "err_thres", err_thres); nuclear@0: printf("maximum error: %f\n", err_thres); nuclear@0: glutPostRedisplay(); nuclear@0: break; nuclear@0: nuclear@0: case '.': nuclear@0: err_thres += 0.001; nuclear@0: set_uniform_float(sdr, "err_thres", err_thres); nuclear@0: printf("maximum error: %f\n", err_thres); nuclear@0: glutPostRedisplay(); nuclear@0: break; nuclear@0: nuclear@0: case 's': nuclear@0: load_shader(); nuclear@0: glutPostRedisplay(); nuclear@0: break; nuclear@1: nuclear@8: case 'S': nuclear@8: use_stereo = !use_stereo; nuclear@8: glutPostRedisplay(); nuclear@8: break; nuclear@8: nuclear@1: case 'r': nuclear@1: reflectivity = reflectivity > 0.0 ? 0.0 : 0.6; nuclear@1: set_uniform_float(sdr, "reflectivity", reflectivity); nuclear@1: glutPostRedisplay(); nuclear@1: break; nuclear@1: nuclear@1: case '`': nuclear@1: { nuclear@1: static bool vis = true; nuclear@1: vis = !vis; nuclear@1: gui_set_visible(vis); nuclear@1: glutPostRedisplay(); nuclear@1: } nuclear@1: break; nuclear@5: nuclear@8: case '[': nuclear@8: eye_sep -= 0.1; nuclear@8: printf("eye separation: %f\n", eye_sep); nuclear@8: glutPostRedisplay(); nuclear@8: break; nuclear@8: nuclear@8: case ']': nuclear@8: eye_sep += 0.1; nuclear@8: printf("eye separation: %f\n", eye_sep); nuclear@8: glutPostRedisplay(); nuclear@8: break; nuclear@8: nuclear@8: nuclear@5: case '\n': nuclear@5: case '\r': nuclear@5: printf("(%.3f %+.3fi %+.3fj %+.3fk) i:%d err: %.4f cam(theta: %.2f phi: %.2f rad: %.2f)\n", seed.w, nuclear@5: seed.x, seed.y, seed.z, iter, err_thres, cam_theta, cam_phi, cam_dist); nuclear@5: break; nuclear@0: } nuclear@1: nuclear@4: imtk_inp_key(key, 1); nuclear@1: glutPostRedisplay(); nuclear@1: } nuclear@1: nuclear@1: void keyb_up(unsigned char key, int x, int y) nuclear@1: { nuclear@4: imtk_inp_key(key, 0); nuclear@1: glutPostRedisplay(); nuclear@0: } nuclear@0: nuclear@0: int bnstate[16]; nuclear@0: nuclear@0: int prev_x = -1, prev_y; nuclear@0: void mouse(int bn, int state, int x, int y) nuclear@0: { nuclear@4: int mod; nuclear@1: nuclear@4: mod = glutGetModifiers(); nuclear@4: nuclear@4: if(mod) { nuclear@1: bnstate[bn] = state == GLUT_DOWN ? 1 : 0; nuclear@1: if(state == GLUT_DOWN) { nuclear@1: if(bn == 3) { nuclear@1: cam_dist -= 0.1; nuclear@1: glutPostRedisplay(); nuclear@1: if(cam_dist < 0) cam_dist = 0; nuclear@1: } else if(bn == 4) { nuclear@1: cam_dist += 0.1; nuclear@1: glutPostRedisplay(); nuclear@1: } else { nuclear@1: prev_x = x; nuclear@1: prev_y = y; nuclear@1: } nuclear@0: } else { nuclear@1: prev_x = -1; nuclear@0: } nuclear@4: } else { nuclear@4: imtk_inp_mouse(bn, state == GLUT_DOWN ? 1 : 0); nuclear@0: } nuclear@1: glutPostRedisplay(); nuclear@0: } nuclear@0: nuclear@0: void motion(int x, int y) nuclear@0: { nuclear@0: if(bnstate[0]) { nuclear@0: cam_theta += (x - prev_x) * 0.5; nuclear@0: cam_phi += (y - prev_y) * 0.5; nuclear@0: nuclear@0: if(cam_phi < -90) cam_phi = -90; nuclear@0: if(cam_phi > 90) cam_phi = 90; nuclear@0: nuclear@0: glutPostRedisplay(); nuclear@0: } nuclear@0: nuclear@0: if(bnstate[1]) { nuclear@0: cam_y += (y - prev_y) * 0.1; nuclear@0: glutPostRedisplay(); nuclear@0: } nuclear@0: nuclear@0: if(bnstate[2]) { nuclear@0: cam_dist += (y - prev_y) * 0.1; nuclear@6: if(cam_dist < 0.0) cam_dist = 0.0; nuclear@0: glutPostRedisplay(); nuclear@0: } nuclear@0: nuclear@0: prev_x = x; nuclear@0: prev_y = y; nuclear@1: nuclear@4: imtk_inp_motion(x, y); nuclear@1: glutPostRedisplay(); nuclear@1: } nuclear@1: nuclear@1: void passive_motion(int x, int y) nuclear@1: { nuclear@4: imtk_inp_motion(x, y); nuclear@4: glutPostRedisplay(); nuclear@0: } nuclear@0: nuclear@6: void sball_motion(int x, int y, int z) nuclear@6: { nuclear@6: float dx = (float)x * 0.0015f; nuclear@6: float dy = (float)y * 0.0015f; nuclear@6: float dz = -(float)z * 0.001f; nuclear@6: float angle = -DEG_TO_RAD(cam_theta); nuclear@6: nuclear@6: cam_x += cos(angle) * dx + sin(angle) * dz; nuclear@6: cam_z += -sin(angle) * dx + cos(angle) * dz; nuclear@6: cam_y += dy; nuclear@6: nuclear@6: glutPostRedisplay(); nuclear@6: } nuclear@6: nuclear@6: void sball_rot(int x, int y, int z) nuclear@6: { nuclear@6: cam_theta += -y / 15.0; nuclear@6: cam_phi += -x / 15.0; nuclear@6: glutPostRedisplay(); nuclear@6: } nuclear@6: nuclear@6: void sball_button(int bn, int state) nuclear@6: { nuclear@6: if(state == GLUT_DOWN) { nuclear@6: switch(bn) { nuclear@6: case 0: nuclear@6: /* TODO reset */ nuclear@6: break; nuclear@6: nuclear@6: default: nuclear@6: break; nuclear@6: } nuclear@6: } nuclear@6: } nuclear@6: nuclear@6: nuclear@0: unsigned int create_ray_texture(int xsz, int ysz, float vfov, Vector2 *tex_scale) nuclear@0: { nuclear@0: unsigned int tex; nuclear@0: int tex_xsz = round_pow2(xsz); nuclear@0: int tex_ysz = round_pow2(ysz); nuclear@0: float *teximg, *dir; nuclear@0: nuclear@0: teximg = new float[3 * tex_xsz * tex_ysz]; nuclear@0: dir = teximg; nuclear@0: nuclear@0: for(int i=0; ix = (float)xsz / (float)tex_xsz; nuclear@0: tex_scale->y = (float)ysz / (float)tex_ysz; nuclear@0: } nuclear@0: return tex; nuclear@0: } nuclear@0: nuclear@0: static Vector3 get_primary_ray_dir(int x, int y, int w, int h, float vfov_deg) nuclear@0: { nuclear@0: float vfov = M_PI * vfov_deg / 180.0; nuclear@0: float aspect = (float)w / (float)h; nuclear@0: nuclear@0: float ysz = 2.0; nuclear@0: float xsz = aspect * ysz; nuclear@0: nuclear@0: float px = ((float)x / (float)w) * xsz - xsz / 2.0; nuclear@0: float py = 1.0 - ((float)y / (float)h) * ysz; nuclear@0: float pz = 1.0 / tan(0.5 * vfov); nuclear@0: nuclear@0: float mag = sqrt(px * px + py * py + pz * pz); nuclear@0: nuclear@0: return Vector3(px / mag, py / mag, pz / mag); nuclear@0: } nuclear@0: nuclear@0: static int round_pow2(int x) nuclear@0: { nuclear@0: x--; nuclear@0: x = (x >> 1) | x; nuclear@0: x = (x >> 2) | x; nuclear@0: x = (x >> 4) | x; nuclear@0: x = (x >> 8) | x; nuclear@0: x = (x >> 16) | x; nuclear@0: return x + 1; nuclear@0: } nuclear@8: nuclear@8: int parse_opt(int argc, char **argv) nuclear@8: { nuclear@8: int i; nuclear@8: nuclear@8: for(i=1; i