/* shadow volume demo * * written by Alexander Zaprjagaev * frustum@public.tsu.ru */ #include #include #include #include #include #include #include "SDL.h" #include "mathlib.h" #include "load3ds.h" #include "sv_mesh.h" #include "mesh.h" #define WIDTH 800 #define HEIGHT 600 int my_pause,my_view; float fps; float phi = -30,psi = -90,dist = 10; float camera[3],dir[3]; float light[4] = { 0, 0, 0, 1 },light_speed = 5,light_rot = 180; float shadow[4] = { 0, 0, 0, 0.5 }; mesh_t *room; sv_mesh_t *staircase,*motor,*cooler,*box,*barrel,*shelf,*mesh; sv_mesh_t *computer,*lcd,*door,*big_wire; float staircase_pos[3] = { 0,0,0 }; float motor_pos[3] = { 0, 5.856, 2.549 }; float cooler_pos[3] = { 0, 4.024, 2.542 },cooler_speed = -30,cooler_rot; float box_pos[3] = { -4.268, 1.343, 3.349 }; float barrel_pos[3] = { -4.301, 3.587, -0.018 }; float shelf_pos[3] = { 4.744, 1.680, 0.215 }; float mesh_pos[3] = { 0, 0, 2.000 },mesh_speed = 20,mesh_rot; float computer_pos[3] = { 4.693, 3.367, 0.654 }; float big_wire_pos[4][3] = {{ 1.004, 0.983, 1.576 }, { 1.004,-1.041, 1.576 }, {-1.004,-1.041, 1.576 }, {-1.004, 0.983, 1.576 }}; float big_wire_rot[4] = { 45, -45, -135, 135 }; /* */ void load_mesh(char *name,float *pos,mesh_t **mesh) { float m[16]; *mesh = mesh_load_3ds(name); if(pos) { m_translate(pos,m); mesh_set_matrix(*mesh,m); } } void load_sv_mesh(char *name,float *pos,sv_mesh_t **mesh) { float m[16]; *mesh = sv_mesh_load_3ds(name); if(pos) { m_translate(pos,m); sv_mesh_set_matrix(*mesh,m); } } /* init */ int init(void) { glClearDepth(1); glClearColor(0,0,0,0); glEnable(GL_LIGHT0); glEnable(GL_CULL_FACE); glEnable(GL_DEPTH_TEST); glDepthFunc(GL_LEQUAL); glPointSize(4); load_mesh("data/room.3ds",NULL,&room); load_sv_mesh("data/staircase.3ds",staircase_pos,&staircase); load_sv_mesh("data/motor.3ds",motor_pos,&motor); load_sv_mesh("data/cooler.3ds",NULL,&cooler); load_sv_mesh("data/box.3ds",box_pos,&box); load_sv_mesh("data/barrel.3ds",barrel_pos,&barrel); load_sv_mesh("data/shelf.3ds",shelf_pos,&shelf); load_sv_mesh("data/mesh.3ds",NULL,&mesh); load_sv_mesh("data/computer.3ds",computer_pos,&computer); load_sv_mesh("data/lcd.3ds",computer_pos,&lcd); load_sv_mesh("data/big_wire.3ds",NULL,&big_wire); return 0; } /* get fps */ float getfps(void) { static float fps = 60; static int starttime,endtime,counter; if(counter == 10) { endtime = starttime; starttime = SDL_GetTicks(); fps = counter * 1000.0 / (float)(starttime - endtime); counter = 0; } counter++; return fps; } /* */ void render(void) { int i; float m0[16],m1[16],m2[16]; glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluPerspective(45,WIDTH / HEIGHT,1,500); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); gluLookAt(camera[0],camera[1],camera[2], dir[0],dir[1],dir[2], 0,0,1); glLightfv(GL_LIGHT0,GL_POSITION,light); glColor3f(1,1,1); /* нарисовали лампочку */ glBegin(GL_POINTS); glVertex3fv(light); glEnd(); /* рисуем все объекты */ glEnable(GL_LIGHTING); mesh_render(room); sv_mesh_render(staircase); sv_mesh_render(motor); sv_mesh_render(cooler); sv_mesh_render(box); sv_mesh_render(barrel); sv_mesh_render(shelf); sv_mesh_render(mesh); sv_mesh_render(computer); sv_mesh_render(lcd); for(i = 0; i < 4; i++) { m_translate(big_wire_pos[i],m0); m_rotation_z(big_wire_rot[i],m1); m_multiply(m0,m1,m2); sv_mesh_set_matrix(big_wire,m2); sv_mesh_render(big_wire); } glDisable(GL_LIGHTING); /* рисуем все тени в стенсиль */ sv_mesh_render_to_stencil(staircase,light); sv_mesh_render_to_stencil(motor,light); sv_mesh_render_to_stencil(cooler,light); sv_mesh_render_to_stencil(box,light); sv_mesh_render_to_stencil(barrel,light); sv_mesh_render_to_stencil(shelf,light); sv_mesh_render_to_stencil(mesh,light); sv_mesh_render_to_stencil(computer,light); sv_mesh_render_to_stencil(lcd,light); for(i = 0; i < 4; i++) { m_translate(big_wire_pos[i],m0); m_rotation_z(big_wire_rot[i],m1); m_multiply(m0,m1,m2); sv_mesh_set_matrix(big_wire,m2); sv_mesh_render_to_stencil(big_wire,light); } /* рисуем тень */ sv_mesh_render_shadow(shadow); SDL_GL_SwapBuffers(); } /* */ void idle(void) { float ifps,rad,v[3],q0[4],q1[4],q2[3],m0[16],m1[16],m2[16]; fps = getfps(); ifps = 1.0 / fps; if(my_pause != 2) cooler_rot += ifps * 360.0 * cooler_speed / 60.0; m_translate(cooler_pos,m0); m_rotation_y(cooler_rot,m1); m_multiply(m0,m1,m2); sv_mesh_set_matrix(cooler,m2); if(my_pause != 2) mesh_rot += ifps * 360.0 * mesh_speed / 60.0; m_translate(mesh_pos,m0); m_rotation_z(mesh_rot,m1); m_multiply(m0,m1,m2); m_rotation_x(mesh_rot / 1.5,m0); m_multiply(m2,m0,m1); sv_mesh_set_matrix(mesh,m1); if(my_pause == 0) light_rot += ifps * 360 * light_speed / 60.0; rad = light_rot * DEG2RAD; v_set(sin(rad) * 3,cos(rad) * 3,0,v); v_set(0,0,2.5,light); v_add(light,v,light); v_set(0,0,1,v); q_set(v,psi,q0); v_set(0,1,0,v); q_set(v,phi,q1); q_multiply(q0,q1,q2); q_to_matrix(q2,m0); v_set(dist,0,0,camera); v_transform(camera,m0,camera); if(my_view == 0) v_copy(mesh_pos,dir) else v_copy(light,dir) v_add(camera,dir,camera); } /* */ void keyboard(int key) { static int wareframe; switch(key) { case SDLK_ESCAPE: SDL_Quit(); exit(0); break; case SDLK_SPACE: my_pause++; if(my_pause == 3) my_pause = 0; break; case SDLK_w: wareframe = !wareframe; glPolygonMode(GL_FRONT_AND_BACK,wareframe ? GL_LINE : GL_FILL); break; case SDLK_v: my_view = !my_view; break; case SDLK_l: light[3] = !light[3]; break; } } /* */ void mouse(int button,int state,int x,int y) { if(button == 4) dist -= 1; if(button == 5) dist += 1; if(dist < 1) dist = 1; if(dist > 100) dist = 100; psi += (x - WIDTH / 2) * 0.2; phi += (y - HEIGHT / 2) * 0.2; if(phi < -89) phi = -89; if(phi > 89) phi = 89; } /* */ int main(int argc,char **argv) { SDL_Surface *screen; int done; SDL_Init(SDL_INIT_VIDEO); screen = SDL_SetVideoMode(WIDTH,HEIGHT,32,SDL_OPENGL | SDL_FULLSCREEN); if(!screen) { printf("couldn`t set video mode: %s\n",SDL_GetError()); SDL_Quit(); exit(1); } init(); SDL_ShowCursor(SDL_DISABLE); SDL_WarpMouse(WIDTH / 2,HEIGHT / 2); done = 0; while(!done) { SDL_Event event; while(SDL_PollEvent(&event)) { switch(event.type) { case SDL_QUIT: done = 1; break; case SDL_KEYDOWN: keyboard(event.key.keysym.sym); break; case SDL_MOUSEMOTION: mouse(0,0,event.motion.x,event.motion.y); break; case SDL_MOUSEBUTTONDOWN: case SDL_MOUSEBUTTONUP: mouse(event.button.button,event.button.state, event.button.x,event.button.y); break; } } SDL_WarpMouse(WIDTH / 2,HEIGHT / 2); idle(); render(); } SDL_Quit(); return 0; }