#ifndef VIEWER_H #define VIEWER_H #include "proj.h" extern GLfloat mat_diffuse_ambient[4]; extern GLfloat mat_specular [4] ; // for floor size #define MAX_X 100 #define MAX_Y 100 #define MIN_X -100 #define MIN_Y -100 typedef enum { R = 0, G = 1, B = 2 } RGB_Coord; // 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; // make a Gl window that draws something: class Gl_Win : public Fl_Gl_Window { public: MotionCapturer *cap; // the meat of it all char in_bvh_name[LINESIZE]; // input bvh file name int cur_time; 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 double *cur_tptr; // pt to trans at this frame double *cur_qptr; // pt to quatern at this frame int rot_cnt; // number of nodes having rotations (roots + joints) int root_cnt; int endsite_cnt; 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 light_pos[4]; bool b_floor; // whether to draw floor bool b_ik; // get in ik mode, enable mosue picking Node *selNode; // the one to do IK on Node *pinNode; // the one got pinned down Point4D gb_goal; double ik_spring_fac; // spring [0,1] double ik_damp; // [0, 1] double ik_sens; Gl_Win(int x, int y, int w, int h); ~Gl_Win(); Status read_input_file (char *filename, Panel* wind, FileType type); /* reads in a motion cap data file. fills a motioncap obj, del old cap if exists. if suceed, init fields in gl_win and changes the framing panel's related UI fields */ 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 */ void do_ik(double gb_goal[4]); void ik_this_bone(bool &b_closer, bool &b_close_enough, Node *targetNode, double rot_sensitive, Bone *bone, JointType joint_type, double gb_goalPos[3]); void write_qbvh(); private: Node *root; double *trans; double *euler; double *quatern; double *expmap; GLUquadricObj *qobj; // for drawing cylinder void draw(); void drawFloor(); // a shadow matrix multiplied onto the stack according to light pos void shadowMatrix(GLfloat light_pos[3]); // bulb slightly below light source, so get lit void draw_light_bulb(bool light, GLfloat light_pos[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); /* 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); void drawSetupTransform(); Node *clickInNode( int mouseDownX, int mouseDownY); /* returns the top Node that was clicked, if hit train and another Node, the one beneath train is returned. returns NULL if no hit. */ void node_lc_to_gbCoord(Node *selNode, double gb_selPos[4]); /* in case we don't have flex file, use default really flexible joint setting recurse set joints lims */ void init_flex(MotionCapturer *cap); bool need_move_root(double gb_goal[3]); void ik_for_node(bool &b_close_enough, Node *targetNode, double gb_goal[4]); }; class Panel : public Fl_Double_Window { public: Gl_Win *gl; Fl_Hold_Browser *euler_browser; Fl_Hold_Browser *quat_browser; Fl_Hold_Browser *emap_browser; Fl_Hold_Browser *marker_type_browser; Fl_Round_Button *key_addB; // for MANU mode Fl_Round_Button *key_rmvB; Fl_Round_Button *key_printB; Fl_Round_Button *key_clearB; Fl_Int_Input *key_nthB; // for AUTO mode Fl_Round_Button *cameraB; Fl_Round_Button *play_modeB; Fl_Int_Input *beginB ; Fl_Int_Input *endB; Fl_Light_Button *lightB; Fl_Light_Button *floorB; 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; }; void del_all(); ~Panel(); }; // 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); #endif