nuclear@0: #include nuclear@0: #include nuclear@0: #include nuclear@0: #include nuclear@0: #include nuclear@0: #include nuclear@0: #include "sdr.h" nuclear@0: nuclear@0: void disp(); nuclear@0: void reshape(int x, int y); nuclear@0: void keyb(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@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@0: float cam_theta = 0, cam_phi = 0, cam_dist = 4.0; nuclear@0: float cam_y = 0; 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@0: 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@0: glutInitDisplayMode(GLUT_RGBA | GLUT_DEPTH | GLUT_DOUBLE); 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@0: glutMouseFunc(mouse); nuclear@0: glutMotionFunc(motion); nuclear@0: nuclear@0: glEnable(GL_DEPTH_TEST); nuclear@0: glEnable(GL_LIGHTING); nuclear@0: glEnable(GL_LIGHT0); nuclear@0: glEnable(GL_CULL_FACE); nuclear@0: nuclear@0: glewInit(); nuclear@0: nuclear@0: if(load_shader() == -1) { nuclear@0: return 1; nuclear@0: } nuclear@0: 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@0: return 0; nuclear@0: } nuclear@0: nuclear@0: void disp() nuclear@0: { nuclear@0: glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); nuclear@0: nuclear@0: glMatrixMode(GL_MODELVIEW); nuclear@0: glLoadIdentity(); 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@0: glMatrixMode(GL_TEXTURE); nuclear@0: glPushMatrix(); nuclear@0: glScalef(tex_scale.x, tex_scale.y, 1.0); nuclear@0: nuclear@0: glBindTexture(GL_TEXTURE_2D, ray_tex); 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@0: glutSwapBuffers(); nuclear@0: assert(glGetError() == GL_NO_ERROR); 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@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@0: } 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@0: bnstate[bn] = state == GLUT_DOWN ? 1 : 0; nuclear@0: if(state == GLUT_DOWN) { nuclear@0: if(bn == 3) { nuclear@0: cam_dist -= 0.1; nuclear@0: glutPostRedisplay(); nuclear@0: if(cam_dist < 0) cam_dist = 0; nuclear@0: } else if(bn == 4) { nuclear@0: cam_dist += 0.1; nuclear@0: glutPostRedisplay(); nuclear@0: } else { nuclear@0: prev_x = x; nuclear@0: prev_y = y; nuclear@0: } nuclear@0: } else { nuclear@0: prev_x = -1; nuclear@0: } 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@0: glutPostRedisplay(); nuclear@0: } nuclear@0: nuclear@0: prev_x = x; nuclear@0: prev_y = y; nuclear@0: } nuclear@0: 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: }