nuclear@0: #include nuclear@0: #include nuclear@0: #include nuclear@0: #include nuclear@0: #include nuclear@0: #include nuclear@0: #include "rend.h" nuclear@0: nuclear@0: static bool init(); nuclear@0: static void cleanup(); nuclear@0: static void display(); nuclear@0: static void reshape(int x, int y); nuclear@0: static void keyb(unsigned char key, int x, int y); nuclear@0: static void mouse(int bn, int st, int x, int y); nuclear@0: static void motion(int x, int y); nuclear@0: static void resize_fbtex(int xsz, int ysz); nuclear@0: static void update_fbtex(); nuclear@0: static int next_pow2(int x); nuclear@0: static float dfunc(float x, float y, float z); nuclear@0: nuclear@0: static int pix_scale = 2; nuclear@0: static int width = 640; nuclear@0: static int height = 384; nuclear@0: static int win_width = width * pix_scale; nuclear@0: static int win_height = height * pix_scale; nuclear@0: nuclear@0: static float *pixels; nuclear@0: static unsigned int tex; nuclear@0: static int tex_width, tex_height; nuclear@0: nuclear@0: static float cam_theta, cam_phi = 25, cam_dist = 10; nuclear@0: nuclear@0: nuclear@0: int main(int argc, char **argv) nuclear@0: { nuclear@0: glutInit(&argc, argv); nuclear@0: glutInitWindowSize(win_width, win_height); nuclear@0: glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE); nuclear@0: glutCreateWindow("distance field raytracer"); nuclear@0: nuclear@0: glutDisplayFunc(display); nuclear@0: glutReshapeFunc(reshape); nuclear@0: glutKeyboardFunc(keyb); nuclear@0: glutMouseFunc(mouse); nuclear@0: glutMotionFunc(motion); nuclear@0: nuclear@0: if(!init()) { nuclear@0: return 1; nuclear@0: } nuclear@0: atexit(cleanup); nuclear@0: nuclear@0: glutMainLoop(); nuclear@0: return 0; nuclear@0: } nuclear@0: nuclear@0: static bool init() nuclear@0: { nuclear@0: glewInit(); nuclear@0: nuclear@0: glEnable(GL_CULL_FACE); nuclear@0: nuclear@0: glGenTextures(1, &tex); nuclear@0: glBindTexture(GL_TEXTURE_2D, tex); nuclear@0: glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); nuclear@0: glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); nuclear@0: nuclear@0: glEnable(GL_TEXTURE_2D); nuclear@0: nuclear@0: set_distance_function(dfunc); nuclear@0: nuclear@0: return true; nuclear@0: } nuclear@0: nuclear@0: static void cleanup() nuclear@0: { nuclear@0: glDeleteTextures(1, &tex); nuclear@0: } nuclear@0: nuclear@0: static void display() nuclear@0: { nuclear@0: Matrix4x4 cmat; nuclear@0: cmat.translate(Vector3(0, 0, -cam_dist)); nuclear@0: cmat.rotate(Vector3(1, 0, 0), DEG_TO_RAD(cam_phi)); nuclear@0: cmat.rotate(Vector3(0, 1, 0), DEG_TO_RAD(cam_theta)); nuclear@0: nuclear@0: set_camera_matrix(cmat); nuclear@0: render(); nuclear@0: update_fbtex(); nuclear@0: nuclear@0: glMatrixMode(GL_TEXTURE); nuclear@0: glLoadIdentity(); nuclear@0: glScalef((float)tex_width / (float)width, (float)tex_height / (float)height, 1); nuclear@0: nuclear@0: glBegin(GL_QUADS); nuclear@0: glTexCoord2f(0, 0); glVertex2f(-1, -1); nuclear@0: glTexCoord2f(1, 0); glVertex2f(1, -1); nuclear@0: glTexCoord2f(1, 1); glVertex2f(1, 1); nuclear@0: glTexCoord2f(0, 1); glVertex2f(-1, 1); nuclear@0: glEnd(); nuclear@0: nuclear@0: glutSwapBuffers(); nuclear@0: assert(glGetError() == GL_NO_ERROR); nuclear@0: } nuclear@0: nuclear@0: static void reshape(int x, int y) nuclear@0: { nuclear@0: static int prev_x , prev_y; nuclear@0: nuclear@0: glViewport(0, 0, x, y); nuclear@0: resize_fbtex(x, y); nuclear@0: nuclear@0: if(x != prev_x || y != prev_y) { nuclear@0: delete [] pixels; nuclear@0: pixels = new float[x * y * 4]; nuclear@0: set_framebuffer(x, y, pixels); nuclear@0: prev_x = x; nuclear@0: prev_y = y; nuclear@0: } nuclear@0: } nuclear@0: nuclear@0: static void resize_fbtex(int xsz, int ysz) nuclear@0: { nuclear@0: int txsz = next_pow2(xsz); nuclear@0: int tysz = next_pow2(ysz); nuclear@0: nuclear@0: if(txsz > tex_width || tysz > tex_height) { nuclear@0: tex_width = txsz; nuclear@0: tex_height = tysz; nuclear@0: nuclear@0: glBindTexture(GL_TEXTURE_2D, tex); nuclear@0: glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16F, txsz, tysz, 0, GL_RGBA, GL_FLOAT, 0); nuclear@0: } nuclear@0: } nuclear@0: nuclear@0: static void update_fbtex() nuclear@0: { nuclear@0: glBindTexture(GL_TEXTURE_2D, tex); nuclear@0: glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, GL_RGBA, GL_FLOAT, pixels); nuclear@0: } nuclear@0: nuclear@0: static int next_pow2(int x) nuclear@0: { nuclear@0: --x; nuclear@0: x |= x >> 1; nuclear@0: x |= x >> 2; nuclear@0: x |= x >> 4; nuclear@0: x |= x >> 8; nuclear@0: x |= x >> 16; nuclear@0: return x + 1; nuclear@0: } nuclear@0: nuclear@0: static float dfunc(float x, float y, float z) nuclear@0: { nuclear@0: return sqrt(x*x + y*y + z*z) - 1.0; nuclear@0: } nuclear@0: nuclear@0: static 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: } nuclear@0: nuclear@0: static int prev_x, prev_y; nuclear@0: static bool bnstate[8]; nuclear@0: nuclear@0: static void mouse(int bn, int st, int x, int y) nuclear@0: { nuclear@0: bnstate[bn - GLUT_LEFT_BUTTON] = st == GLUT_DOWN; nuclear@0: prev_x = x; nuclear@0: prev_y = y; nuclear@0: } nuclear@0: nuclear@0: static void motion(int x, int y) nuclear@0: { nuclear@0: int dx = x - prev_x; nuclear@0: int dy = y - prev_y; nuclear@0: prev_x = x; nuclear@0: prev_y = y; nuclear@0: nuclear@0: if(!dx && !dy) return; nuclear@0: nuclear@0: if(bnstate[0]) { nuclear@0: cam_theta -= dx * 0.5; nuclear@0: cam_phi -= dy * 0.5; nuclear@0: nuclear@0: if(cam_phi < -90) cam_phi = -90; nuclear@0: if(cam_phi > 90) cam_phi = 90; nuclear@0: glutPostRedisplay(); nuclear@0: } nuclear@0: if(bnstate[2]) { nuclear@0: cam_dist += dy * 0.1; nuclear@0: if(cam_dist < 0.0) cam_dist = 0.0; nuclear@0: glutPostRedisplay(); nuclear@0: } nuclear@0: }