// copyright Min Zhong, cs838 proj2, April, 2000 // $Header: /p/graphics/CVS/638/Web/Examples/GL/RunButton.cpp,v 1.1 1999/10/20 16:25:05 gleicher Exp $ // // CS638 Example code - this provides a utility routine to help with animation // written October, 1999 by Michael L. Gleicher // // This file implements a "play" button. The idea is that you creat a window that // does your drawing. When redrawing, this window looks at a slider to see what // time it is, so it knows what part of the animation to draw. // // The slider must call the window's redraw function whenever the time changes. // // The play button, when pressed, advances the slider forward a timestep continually. // In order to do this, it installs itself in the FlTk "Idle" loop so it gets called // periodically. // #include "RunButton.H" #include "viewer.h" // this is the regular fltk callback for run button void runCB(Fl_Widget* wid, Fl_Widget* o) { o->damage(1); } // the slider constructor RunSlider::RunSlider(Fl_Widget* dr, int length, int x, int y, int w, int h) : Fl_Value_Slider(x,y,w,h) { // set up slider parameters value(0); range(0,length-1); step(1); type(5); // horizontal, "nice" when(FL_WHEN_CHANGED); // update whenever it changes callback((Fl_Callback*) runSliderCB, dr); } // // this callback function is the "guts" of the RunButton - // notice that it is an "idle" callback, not a widget callback // // another nice problem to have - most likely, we'll be too fast // don't draw more than 30 times per second void runButtonCB(RunButton* b) { int cur_ticks = (int) clock(); // cur time in ticks if (b->value()) { // only advance time if appropriate long ticks_so_far = (cur_ticks - b->firstRedraw) % (long) (b->ticks_tot); long ticks_since_last = (cur_ticks - b->lastRedraw); int frame_to_draw; // need to draw a frame if (b->mode == REAL_TIME) { if ( ticks_since_last > b->ticks_per_frame) { b->lastRedraw = cur_ticks; // update lastRedraw time frame_to_draw = (int) (ticks_so_far / b->ticks_tot * b->frame_cnt) + (int) b->slider->minimum(); b->slider->value(frame_to_draw); // when the value is changed internally (b->slider->callback())(b->slider,b->slider->user_data()); } } else if (b->mode == CONST_SPD) { if ( ticks_since_last > CLOCKS_PER_SEC / 30) { int frame_max = (int) b->slider->maximum(); frame_to_draw = (int) b->slider->value(); frame_to_draw ++; if (frame_to_draw > frame_max) frame_to_draw = (int) b->slider->minimum(); // wrap around b->slider->value(frame_to_draw); // note: FlTk doesn't have the slider call its callback // when the value is changed internally (b->slider->callback())(b->slider,b->slider->user_data()); } } // if need to draw } } // create the run button - the main thing it does is install the idle // handler RunButton::RunButton(Fl_Slider* timeS, int x, int y, int w, int h, double in_frame_time, PLAYMODE in_mode) : Fl_Light_Button(x,y,w,h,"Play") { slider = timeS; init_ticks(in_frame_time, in_mode); } // init tick counters, called every time a new first motion file loaded RunButton::init_ticks(double in_frame_time, PLAYMODE in_mode) { Fl::remove_idle((void (*)(void*))runButtonCB,this); lastRedraw = 0; firstRedraw = 0; ticks_per_frame = (in_frame_time * CLOCKS_PER_SEC); frame_cnt = ((int) slider->maximum() - (int)slider->minimum() + 1); ticks_tot = ticks_per_frame * frame_cnt; mode = in_mode; Fl::add_idle((void (*)(void*))runButtonCB,this); } RunButton::~RunButton() { Fl::remove_idle((void (*)(void*))runButtonCB,this); }