// copyright Min Zhong, cs838 proj2, April, 2000 #ifndef VIEWER_H #define VIEWER_H #include "proj2.h" extern GLfloat mat_diffuse_ambient[4]; extern GLfloat mat_specular [4] ; // for floor size #define MAX_X 50 #define MAX_Y 50 #define MIN_X -50 #define MIN_Y -50 typedef enum { R = 0, G = 1, B = 2 } RGB_Coord; // rotation type typedef enum { EULER = 1, QUAT = 2, EXPMAP = 3 } RotType; // interp type typedef enum { HIDE = 1, NONE = 2, LINEAR = 3, SLERP = 4, EM_SLERP = 5, EM_LIN = 6, CARDINAL = 7, Q_BERZIER = 8 } InterpType; typedef enum { OMIN = 1, FOLLOW = 2 } CameraViewType; class MotionCapturer; class RunButton; class RunSlider; class Panel; class Marker; typedef struct Node Node; typedef struct MarkerDrawn MarkerDrawn; extern void show_viewer( MotionCapturer *cap ); // the main routine makes the window, and then runs an even loop // make a Gl window that draws something: class Gl_Win : public Fl_Gl_Window { public: MotionCapturer *cap; // the meat of it all bool b_readSuceed; // true if data file read in successful RunSlider *timeS; // slider that tells what time the animation is at. RunButton *runBut; // play but, drives slider PLAYMODE play_mode; // real time or const spd double frame_time; int frame_cnt; int *keyTimes; // max = number of frames. int key_cnt; // number of keys to be used int begin; // first frame to be disp int end; // last frame to be disp InterpType e_interpType; // euler interp method (none, lin, cubic) InterpType q_interpType; // quat interp method (none, slerp, cubic) InterpType m_interpType; // exp map interp method (none, lin, cubic) bool b_need_reinterp; // set when keys change RotType m_rotType; Marker *marker_head; // for markers read in from file Marker *marker_endsite; // a list of end site markers MarkerDrawn *endsites_draw; // has a bool assoc w/ each marker, decides which to be drawn Fl_Multi_Browser *endsite_browser; // for sel marker to be drawn CameraViewType cameraView; bool light; GLfloat light0_position[4]; bool b_floor; // whether to draw floor Gl_Win(int x, int y, int w, int h); ~Gl_Win(); void read_input_file (Panel* wind); /* reads in a motion cap data file. fills a motioncap obj, del old cap if exists. if suceed, set b_readSuceed and init fields in gl_win. changes the framing fl_double win's title to include the data file name */ Status key_nth( int nth); /* if nth is a valid num, store evyer nth frame in keyTimes + always key f(0) and f(frame_cnt-1), set b_need_reinterp */ Status key_add(int frameIdx); /* if this frame not in keyTimes array already, add it, inc key_cnt, set b_need_reinterp to true */ void disp_keyTimes(); /* prints all key times */ Status key_remove( int frameIdx); /* remove a specified key frame, decr key_cnt, set b_need_reinterp */ Status read_marker_request(Marker* &m_head); /* reads in a marker request file, allocates markers. */ Status calc_markers_pos(Marker *m_head, RotType rotType); Status export_markers(Marker *m_head); /* export marker's global pos at each frame to file */ void camera_follow(int time, double look[3], double eye[3]); /* changes look and eye given time, follow_theta, follow_phi, follow_lag, and pos and rot at the time */ private: Node *root; double *trans; double *euler; double *quatern; double *expmap; int rot_cnt; // number of nodes having rotations (roots + joints) int root_cnt; int endsite_cnt; GLUquadricObj *qobj; // for drawing cylinder void draw(); void drawFloor(); // a shadow matrix multiplied onto the stack according to light pos void shadowMatrix(GLfloat light0_position[3]); // try to set the light at center of the action and 100 above. void light_pos(int frame_cnt, double *trans, GLfloat light0_position[3]); // bulb slightly below light source, so get lit void draw_light_bulb(bool light, GLfloat light0_position[3]); // invokes real drawing blocks. if !shadow then draw in color/light void drawObjs(bool shadows, bool light, int cur_time); void draw_frame_of_interpType(RotType rotType, InterpType interpType, double *t_ptr, double *ref_rptr, double *intrp_rptr); void draw_a_frame( Node *root, RotType rotType, double *trans, double* rot, bool isRoot); /* assoc a bool w/ each marker in this marker list to decide which need to be drawn fill in the global coord for each marker for all frames */ void init_marker_draw(RotType m_rotType, Node *root, Marker* m_head, Fl_Multi_Browser *marker_browser, MarkerDrawn* &m_drawlist, int endsite_cnt); int handle(int e); // event handler // screen size int w; int h; // store the viewing parameters - these may get changed as the user // moves things around double eye[3]; double look[3]; double follow_theta; double follow_phi; double follow_lag; double fieldOfView; void init_with_cap(); // if cap not null, fill in appropriate data fields in Gl_Win void interp( InterpType interpType ) ; /* fills in frames bw frame keyTimes[first_keyIdx] and frame keyTimes[first_keyIdx+1] inclusive rot holds the interpolated data interp from ref_rot */ void interp_bw2(int first_keyIdx, InterpType interpType, double *ref_rot, double *rot, int tuple_size); /* interp cubic deg bezier quat spline seg bw 4 ctrl pts keyTimes[first_keyIdx], keyTimes[first_keyIdx+3]*/ void interp_bw4_qSpline(int first_keyIdx, double *ref_rot, double *rot, int tuple_size); // draw markers from frame begin to end void draw_markers(RotType m_rotType, Marker *m_head, int begin_frame, int end_frame); // draw selected markers void draw_sel_markers(MarkerDrawn *m_draw, int m_cnt, int begin_frame, int end_frame); void del_markers(Marker* &m_head); }; class Panel : public Fl_Double_Window { public: Gl_Win *gl; Fl_Button *in_motion_fileB; Fl_Hold_Browser *euler_browser; Fl_Hold_Browser *quat_browser; Fl_Hold_Browser *emap_browser; Fl_Round_Button *key_addB; // for MANU mode Fl_Round_Button *key_rmvB; Fl_Int_Input *key_nthB; // for AUTO mode Fl_Int_Input *beginB ; Fl_Int_Input *endB; RunButton *runBut; // drives the slider Panel(int x, int y, int in_w, int in_h) : Fl_Double_Window(x,y,in_w,in_h,"GL Motion Capture:") { gl = NULL; }; ~Panel(); }; // vector v2 = glmat * v1, glmat is a col major mat void glmat44_mult_vec41(double *mat, double *v1, double *v2); // recursively find all end sites and make a marker list for it void create_endsite_marker_list(Node *parent, Node *root, int f_cnt, Marker* &m_head, int &endsite_cnt); /* returns a double[16] params [a1,b1,c1,d1; a2 b2 c2 d2; a3 b3 c3 d3; a4 b4 c4 d4] for calc interp vars 1,2,3,4 (e.g. x,y,z,w) in: double *p0, *p1; // control points for interp on seg b/w t1 and t2 tuple_size, offset to skip over each time step, 3 for euler/expmap, 4 for quat ASSUME caller alloc mem for params */ void calc_lin_curveParams(double *p0, double *p1, int t1, int t2, double *params); // init an input button's label align and assign init val void init_int_input_button(Fl_Int_Input *b, int align, int init_val); // a quick and dirty hack for rotating the eyepoint // Gleicher's code void orbit(int mx, int my, double lx, double ly, double lz, double ex, double ey, double ez, double& rx, double& ry, double& rz); // if mouse stroke to left: zoomOut; to right: zoomIn void zoom(int mouseDragXdist, double &fieldOfView); // remove all keys void key_clearCB(Fl_Widget* wid, Fl_Widget *container); // remove this key void key_rmvCB(Fl_Widget* wid, Fl_Widget *container); // print all keys void key_printCB(Fl_Widget* wid, Fl_Widget *container); // key every nth frame. void key_nthCB(Fl_Widget* wid, Fl_Widget *container); // key the frame slider is at void key_addCB(Fl_Widget* wid, Fl_Widget *container); // begin frame button cb void beginCB(Fl_Widget* wid, Fl_Widget *container); // end frame button cb void endCB(Fl_Widget* wid, Fl_Widget *container); // switch bw real time and const spd play back void play_modeCB(Fl_Widget* wid, Fl_Widget *container); // open input file button callback void in_motion_fileCB(Fl_Widget* wid, Fl_Widget *container); // choose euler interp options and invoke appropriate interp routine void euler_browserCB(Fl_Widget* wid, Fl_Widget *container); // choose quat interp options and invoke appropriate interp routine void quat_browserCB(Fl_Widget* wid, Fl_Widget *container); // choose exp map interp options and invoke appropriate interp routine void emap_browserCB(Fl_Widget* wid, Fl_Widget *container); // load marker request file void in_marker_fileCB(Fl_Widget* wid, Fl_Widget *container); // write marker coord to file void out_marker_fileCB(Fl_Widget* wid, Fl_Widget *container); // choose whether and how to show markers (which rotation to use) void marker_rotType_browserCB(Fl_Widget* wid, Fl_Widget *container); // sel markers to be drawn void marker_sel_browserCB(Fl_Widget* wid, Fl_Widget *container); // turn on the light src void lightCB(Fl_Widget* in_slider, Fl_Widget* in_wind); // draw the floor void floorCB(Fl_Widget* in_slider, Fl_Widget* in_wind); // sel camera view void camera_browserCB(Fl_Widget* wid, Fl_Widget *container); void camera_omin(int frame_cnt, double *trans, double look[3], double eye[3]); void adjust_follow_theta(int mouseDragXdist, double &follow_theta); void adjust_follow_phi(int mouseDragYdist, double &follow_phi); void adjust_follow_lag(int mouseDragXdist, double &follow_lag); void set_light1( double pos[3], double spot_dir[3] ); #endif