c++ - How to manage code to display animation only once? -
i making program animate ball on field goes like,
void display() { /* code draw field */ loop:1 5 loop:1 6 /* here comes code animate ball on field */ }
i want whenever user press "right_arrow" whole scene rotated by
angle
problem:whenever user presses "right_arrow" key rotate scene angle display whole animation again...but want animation displayed once(after maximazing window) , user can rotate whole scene
angle without displaying animation on pressing "right_arrow" key
how should in code?
again problem lies in mistake animation in display function. extended example wrote yesterday bit; after starting program, animation play 5 seconds, stop. pressing [r] resets animation (thus starts again), pressing [+] / [-] rotates scene around y axis.
http://homepages.physik.uni-muenchen.de/~wolfgang.draxinger/stuff/sinsphere_rot.c edit: commenting
/* ansi-c - don't try compile c++ compiler, fail! */ #include <gl/glut.h> #include <stdlib.h> #include <sys/time.h> #include <math.h> #define m_pi 3.1415926535897932384626433832795029l #define m_pi_2 1.5707963267948966192313216916397514l # define timersub(a, b, result) \ { \ (result)->tv_sec = (a)->tv_sec - (b)->tv_sec; \ (result)->tv_usec = (a)->tv_usec - (b)->tv_usec; \ if ((result)->tv_usec < 0) { \ --(result)->tv_sec; \ (result)->tv_usec += 1000000; \ } \ } while (0) void idle(void); void animate(float dt); void display(void); void keyboard(unsigned char key, int x, int y); void init_sphere(unsigned int rings, unsigned int sectors); void draw_sphere(void); int main(int argc, char *argv[]) { glutinit(&argc, argv); glutinitdisplaymode(glut_rgba | glut_double); glutcreatewindow("sinsphere"); glutidlefunc(idle); glutkeyboardfunc(keyboard); glutdisplayfunc(display); init_sphere(10, 30); glutmainloop(); return 0; }
this boilerplate code, nothing special.
struct animationstate { float time; float duration; float sphere_speed; float sphere_path_radius; float sphere_path_bobbing; float sphere_position[3]; }; static struct animationstate animation = { 0., 5., /* play 5 seconds */ 0.1, 3., 1., {1., 0., 0.} };
animationstate got additional element duration
; after time animation stop playing, testing if animation.time < animation.duration
, advance animation step if so.
void animate(float dt) { if(animation.time < animation.duration) { animation.time += dt; animation.sphere_position[0] = animation.sphere_path_radius * cos(2*m_pi * animation.time * animation.sphere_speed); animation.sphere_position[1] = animation.sphere_path_bobbing * sin(2*m_pi * animation.time * 5 * animation.sphere_speed); animation.sphere_position[2] = animation.sphere_path_radius * sin(2*m_pi * animation.time * animation.sphere_speed); } } struct viewstate { float rotation; float rotation_step; }; static struct viewstate view = { 0., 0.1 };
viewstate stores rotation. dumbed down version, implements through view transformation matix , steppings that.
void keyboard(unsigned char key, int x, int y) { switch(key) { case 'r': case 'r': /* restart animation */ animation.time = 0.; break; case '+': view.rotation += view.rotation_step; break; case '-': view.rotation -= view.rotation_step; break; } glutpostredisplay(); }
keyboard handler function should obvious.
glfloat *sphere_vertices_normals; unsigned int sphere_quads = 0; glushort *sphere_indices; void init_sphere(unsigned int rings, unsigned int sectors) { float const r = 1./(float)(rings-1); float const s = 1./(float)(sectors-1); int r, s; sphere_vertices_normals = malloc(sizeof(glfloat)*3 * rings*sectors); glfloat *v = sphere_vertices_normals; for(r = 0; r < rings; r++) for(s = 0; s < sectors; s++) { float const y = sin( -m_pi_2 + m_pi * r * r ); float const x = cos(2*m_pi * s * s) * sin( m_pi * r * r ); float const z = sin(2*m_pi * s * s) * sin( m_pi * r * r ); v[0] = x; v[1] = y; v[2] = z; v+=3; } sphere_indices = malloc(sizeof(glushort) * rings * sectors * 4); glushort *i = sphere_indices; for(r = 0; r < rings; r++) for(s = 0; s < sectors; s++) { *i++ = r * sectors + s; *i++ = r * sectors + (s+1); *i++ = (r+1) * sectors + (s+1); *i++ = (r+1) * sectors + s; sphere_quads++; } }
init_sphere
build nice vertex , index array containing sphere geometry. exercise reader: put in vertex buffer object.
void draw_sphere() { gltranslatef(animation.sphere_position[0], animation.sphere_position[1], animation.sphere_position[2]); glenableclientstate(gl_vertex_array); glenableclientstate(gl_normal_array); glvertexpointer(3, gl_float, 0, sphere_vertices_normals); glnormalpointer(gl_float, 0, sphere_vertices_normals); gldrawelements(gl_quads, sphere_quads*4, gl_unsigned_short, sphere_indices); } void idle() { glutpostredisplay(); }
the idle function gets called after input events have been processed. input events keypresses , like. glut events processed after display handler returns. must not implement animation timer loop within display handler. instead determine time single display, advance loop timestep next display iteration. idle
initiate next display pass after event processing.
static glfloat const light_pos[4] = {-1., 1., 1., 0.}; static glfloat const light_color[4] = {1., 1., 1., 1.}; void display() { static struct timeval delta_t = {0., 0.}; struct timeval time_frame_begin, time_frame_end; int win_width, win_height; float win_aspect; gettimeofday(&time_frame_begin, 0); animate(delta_t.tv_sec + delta_t.tv_usec * 1.e-6); win_width = glutget(glut_window_width); win_height = glutget(glut_window_height); win_aspect = (float)win_width/(float)win_height; glviewport(0, 0, win_width, win_height); glclearcolor(0.6, 0.6, 1.0, 1.0); glclear(gl_color_buffer_bit | gl_depth_buffer_bit); glmatrixmode(gl_projection); glloadidentity(); glfrustum(-win_aspect, win_aspect, -1., 1., 1., 10.); glmatrixmode(gl_modelview); glloadidentity(); gltranslatef(0,0,-5.5); glrotatef(view.rotation * 180./m_pi, 0, 1, 0); gllightfv(gl_light0, gl_position, light_pos); gllightfv(gl_light0, gl_diffuse, light_color); glpushmatrix(); glenable(gl_depth_test); glenable(gl_lighting); glenable(gl_light0); draw_sphere(); glpopmatrix(); glutswapbuffers(); gettimeofday(&time_frame_end, 0); timersub(&time_frame_end, &time_frame_begin, &delta_t); }
instead of measureing time spent in display
more accurate approach measuring time between each invocation of display
take time spent in other parts of programm account. exercise left reader.
Comments
Post a Comment