#include "viewer.h" #include "RunButton.h" #include "Marker.h" #include "vector.h" // returns a file name if gets it ok, NULL otherwise char *get_file_name( FileType type); bool CLOSE_TO_ZERO( double a) { return ( (a)>=0 ? (a) - NEAR_ZERO ); } // if a is close to a target bool CLOSE_TO( double a, double target) { double diff = a - target; return ( diff>=0 ? (diff) - NEAR_ZERO ); } void ik_springCB(Fl_Value_Slider *s, Gl_Win *gl) { gl->ik_spring_fac = s->value(); } void ik_dampCB(Fl_Value_Slider *s, Gl_Win *gl) { gl->ik_damp = s->value(); } void ik_sensitiveCB(Fl_Value_Slider *s, Gl_Win *gl) { gl->ik_sens = s->value(); } // curtesy of gleicher's code // a quick and dirty hack for rotating the eyepoint // note: although this is modeled after the virtual sphere, its // much simple and (probably) not as good // it takes a lookat/eye pair and moves the eye around the lookat point // based on some wierd notions of how far to go, given how far the mouse moved // from the beginning // the fundamental flaw of this method is that it rotates around fixed axes // so, in a way, its instructive to use it to learn about gimbal lock // I often find that I cannot rotate the world the way that i want with this // interface void orbit(int mx, int my, double lx, double ly, double lz, double ex, double ey, double ez, double& rx, double& ry, double& rz) { // // first - if the mouse motion is small, return to starting position // this should make it easier to move around 1 axis if (mx<0) { mx = mx+5; if (mx>0) mx = 0; } else { mx = mx-5; if (mx<0) mx = 0; } if (my<0) { my = my+5; if (my>0) my = 0; } else { mx = mx-5; if (my<0) my = 0; } // make the center of the coordinate system be the lookat point so that's // where we rotate about ex -= lx; ey -= ly; ez -= lz; // horizontal motions rotate around the vertical (y axis) by an amount // proportional to the amount the mouse moved - the amount is pretty // arbitrary double hz = ((double) mx) / 200; double sx = sin(hz); double cx = cos(hz); rx = cx * ex - sx * ez; rz = sx * ex + cx * ez; // note: rotating around the z (or x) axis isn't really right, but its // easy double vt = ((double) my) / 200; double sz = sin(vt); double cz = cos(vt); ex = rx; // for safe keeping rx = cz * ex - sz * ey; ry = sz * ex + cz * ey; // shift the result back so that the lookat point is in the right place rx += lx; ry += ly; rz += lz; } // the guts of the slider - void runSliderCB(Fl_Widget* in_slider, Fl_Widget* in_wind) { RunSlider *slider = (RunSlider *)in_slider; Panel *wind = (Panel *)in_wind; Gl_Win *gl = wind->gl; int r_off; // rot arr offset to get to this frame wind->key_addB->value(0); wind->key_rmvB->value(0); if (gl->cap == NULL) return; gl->cur_time = (int) ( gl->timeS->value() ) % gl->frame_cnt; gl->cur_tptr = gl->cap->trans + gl->cur_time * 3; r_off = gl->cur_time * 4 * gl->rot_cnt; if (gl->q_interpType == NONE || gl->q_interpType == HIDE) gl->cur_qptr = gl->cap->quatern + r_off; else gl->cur_qptr = gl->cap->qinterp + r_off; gl->damage(1); } // switch bw real time and const spd play back void play_modeCB(Fl_Widget* wid, Fl_Widget *container) { RunButton *but = (RunButton *)wid; Gl_Win *win = (Gl_Win *)container; if (win->play_mode == REAL_TIME) { win->play_mode = CONST_SPD; but->value(0); } else if (win->play_mode == CONST_SPD) { win->play_mode = REAL_TIME; but->value(1); } win->runBut->init_ticks(win->frame_time, win->play_mode); win->damage(1); } // sel camera view void cameraCB(Fl_Round_Button *b, Gl_Win *win) { if (b->value() == 0) win->cameraView = OMIN; else { if ( win->cap == NULL ) { // no motion file loaded fl_alert("Load Motion file first."); b->value(0); return; } else win->cameraView = FOLLOW; } win->damage(1); } // remove all keys void key_clearCB(Fl_Widget* wid, Fl_Widget *container) { Fl_Round_Button *but = (Fl_Round_Button *)wid; Panel *wind = (Panel *)container; Gl_Win *gl = wind->gl; but->value(1); gl->key_cnt = 0; // set key cnt to 0 if (gl->e_interpType != HIDE && gl->e_interpType != NONE) gl->e_interpType = HIDE; wind->euler_browser->value(HIDE); if (gl->q_interpType != HIDE && gl->q_interpType != NONE) gl->q_interpType = HIDE; wind->quat_browser->value(HIDE); if (gl->m_interpType != HIDE && gl->m_interpType != NONE) gl->m_interpType = HIDE; wind->emap_browser->value(HIDE); but->value(0); wind->damage(1); } // print all keys void key_printCB(Fl_Widget* wid, Fl_Widget *container) { Fl_Round_Button *but = (Fl_Round_Button *)wid; Gl_Win *win = (Gl_Win *)container; but->value(1); win->disp_keyTimes(); but->value(0); } // key the frame slider is at void key_addCB(Fl_Widget* wid, Fl_Widget *container) { Fl_Round_Button *but = (Fl_Round_Button *)wid; Panel *wind = (Panel *)container; Gl_Win *gl = wind->gl; if (gl->keyTimes == NULL) { fl_alert("Load Motion file first."); but->value(0); } else { but->value(1); if ( gl->key_add((int) gl->timeS->value()) == SUCCESS ) { wind->key_rmvB->value(0); // turn off remove but if it were on at that frame wind->damage(1); } } } // remove this key void key_rmvCB(Fl_Widget* wid, Fl_Widget *container) { Fl_Round_Button *but = (Fl_Round_Button *)wid; Panel *wind = (Panel *)container; Gl_Win *gl = wind->gl; if (gl->keyTimes == NULL) { fl_alert("Load Motion file first."); but->value(0); } else { but->value(1); if ( gl->key_remove((int) gl->timeS->value()) == SUCCESS ) { wind->key_addB->value(0); // turn off the key_add but if (gl->key_cnt == 0) { // no interp allowed if no key if (gl->e_interpType != HIDE && gl->e_interpType != NONE) gl->e_interpType = HIDE; wind->euler_browser->value(HIDE); if (gl->q_interpType != HIDE && gl->q_interpType != NONE) gl->q_interpType = HIDE; wind->quat_browser->value(HIDE); if (gl->m_interpType != HIDE && gl->m_interpType != NONE) gl->m_interpType = HIDE; wind->emap_browser->value(HIDE); } wind->damage(1); } else { fl_alert("This frame was not keyed."); } } } // sets up gl_win's keytimes array to key every nth frame. void key_nthCB(Fl_Widget* wid, Fl_Widget *container) { Fl_Int_Input *but = (Fl_Int_Input *)wid; Panel *win = (Panel *)container; int nth = atoi( but->value() ); if (win->gl->keyTimes == NULL) { fl_alert("Load Motion file first."); but->value(0); } else if (nth >= win->gl->frame_cnt || nth <= 0 ) fl_alert("invalid nth frame. Range: [1, %d]", win->gl->frame_cnt-1 ); else if (win->gl->key_nth( nth ) == SUCCESS) win->damage(1); } // begin frame button cb void beginCB(Fl_Widget* wid, Fl_Widget *container) { Fl_Int_Input *but = (Fl_Int_Input *)wid; Gl_Win *win = (Gl_Win *)container; int new_begin = atoi( but->value() ); char s_old_begin[10]; if (new_begin == win->begin || new_begin < 0 ) {// no change fl_alert("invalid beginning. Range: [0, %d]", win->frame_cnt-1 ); // reset to old val _itoa(win->begin, s_old_begin, 10); but->value(s_old_begin); return; } win->begin = new_begin; win->timeS->range(new_begin, win->end); win->timeS->minimum(new_begin); win->runBut->init_ticks(win->frame_time, win->play_mode); } // end frame button cb void endCB(Fl_Widget* wid, Fl_Widget *container) { Fl_Int_Input *but = (Fl_Int_Input *)wid; Gl_Win *win = (Gl_Win *)container; int new_end = atoi( but->value() ); char s_old_end[10]; if (new_end == win->end || new_end >= win->frame_cnt ) {// no change fl_alert("invalid end. Range: [0, %d]", win->frame_cnt-1 ); // reset to old val _itoa(win->end, s_old_end, 10); but->value(s_old_end); return; } win->end = new_end; win->timeS->range(win->begin, new_end); win->timeS->maximum(new_end); win->runBut->init_ticks(win->frame_time, win->play_mode); } // returns a file name if gets it ok, NULL otherwise char *get_file_name( FileType type) { char* filename; filename = NULL; if (type == BVH) filename = fl_file_chooser("Enter file name to load ", "*.bvh", NULL); else if (type == QBVH) filename = fl_file_chooser("Enter file name to load ", "*.qbvh", NULL); else //invlaid type filename = NULL; return filename; } // open input file button callback void in_bvhCB(Fl_Menu_*, Panel *win) { Gl_Win *gl = win->gl; char *filename = get_file_name( BVH ); Status status = gl->read_input_file(filename, win, BVH); if (status == SUCCESS) win->damage(1); else fl_alert("invalid motion file.\n"); } // quat ver of bvh void in_qbvhCB(Fl_Menu_*, Panel *win) { Gl_Win *gl = win->gl; char *filename = get_file_name( QBVH ); Status status = gl->read_input_file(filename, win, QBVH); if (status == SUCCESS) win->damage(1); else fl_alert("invalid motion file.\n"); } // quat ver of bvh void out_qbvhCB(Fl_Menu_*, Panel *win) { Gl_Win *gl = win->gl; if (gl->cap == NULL) { fl_alert("No Motion to be written."); } else gl->write_qbvh(); } // load marker request file void in_marker_fileCB(Fl_Widget* wid, Gl_Win *win) { if (win->cap == NULL) { fl_alert("Load Motion file first."); } else if (win->read_marker_request(win->marker_head) == SUCCESS) { if (win->calc_markers_pos(win->marker_head, win->m_rotType) == SUCCESS) win->damage(1); else fl_alert("Invalid Joint in marker file."); } } // write marker coord to file void out_marker_fileCB(Fl_Widget* wid, Gl_Win *win) { if (win->cap == NULL) { fl_alert("Load Motion file first."); } else win->export_markers(win->marker_head); } // choose whether and how to show markers (which rotation to use) void marker_rotType_browserCB(Fl_Widget* wid, Fl_Widget *container) { Fl_Hold_Browser *b = (Fl_Hold_Browser *)wid; Gl_Win *win = (Gl_Win *)container; RotType old_m = win->m_rotType; switch (b->value()) { case 1: win->m_rotType = EULER; break; case 2: win->m_rotType = QUAT; break; case 3: win->m_rotType = EXPMAP; break; default: return; } if (win->m_rotType != old_m) { win->calc_markers_pos(win->marker_endsite, win->m_rotType); // recalc for all endsites if (win->marker_head != NULL) if (win->calc_markers_pos(win->marker_head, win->m_rotType) != SUCCESS) fl_alert("Invalid Joint in marker file."); // should't happen win->damage(1); } } // choose euler interp options and invoke appropriate interp routine void euler_browserCB(Fl_Widget* wid, Fl_Widget *container) { Fl_Hold_Browser *b = (Fl_Hold_Browser *)wid; Gl_Win *win = (Gl_Win *)container; InterpType old_interp = win->e_interpType; switch (b->value()) { case 1: win->e_interpType = HIDE; break; case 2: win->e_interpType = NONE; break; case 3: if (win->key_cnt < 2) { fl_alert("set more keys first."); b->value(old_interp); return; } else { win->e_interpType = LINEAR; if (old_interp != win->e_interpType ) win->b_need_reinterp = true; } break; case 4: if (win->key_cnt < 4) { fl_alert("set more keys first."); b->value(old_interp); return; } else { win->e_interpType = CARDINAL; if (old_interp != win->e_interpType ) win->b_need_reinterp = true; } break; default: return; } if (old_interp != HIDE && old_interp != NONE && (win->e_interpType == NONE || win->e_interpType == HIDE) && win->m_rotType == EULER) { // going from interp ->non-interp win->calc_markers_pos(win->marker_endsite, EULER); if (win->marker_head != NULL) win->calc_markers_pos(win->marker_head, EULER); } win->damage(1); } // choose quat interp options and invoke appropriate interp routine void quat_browserCB(Fl_Widget* wid, Fl_Widget *container) { Fl_Hold_Browser *b = (Fl_Hold_Browser *)wid; Gl_Win *win = (Gl_Win *)container; InterpType old_interp = win->q_interpType; switch (b->value()) { case 1: win->q_interpType = HIDE; break; case 2: win->q_interpType = NONE; break; case 3: if (win->key_cnt < 2) { fl_alert("set more keys first."); b->value(old_interp); return; } else { win->q_interpType = SLERP; if (old_interp != win->q_interpType ) win->b_need_reinterp = true; } break; case 4: if (win->key_cnt < 4) { fl_alert("set more keys first."); b->value(old_interp); return; } else { win->q_interpType = Q_BERZIER; if (old_interp != win->q_interpType ) win->b_need_reinterp = true; } break; default: return; } if (old_interp != HIDE && old_interp != NONE && (win->q_interpType == NONE || win->q_interpType == HIDE) && win->m_rotType == QUAT) { // going from interp ->non-interp win->calc_markers_pos(win->marker_endsite, QUAT); if (win->marker_head != NULL) win->calc_markers_pos(win->marker_head, QUAT); } win->damage(1); } // choose exp map interp options and invoke appropriate interp routine void emap_browserCB(Fl_Widget* wid, Fl_Widget *container) { Fl_Hold_Browser *b = (Fl_Hold_Browser *)wid; Gl_Win *win = (Gl_Win *)container; InterpType old_interp = win->m_interpType; switch (b->value()) { case 1: win->m_interpType = HIDE; break; case 2: win->m_interpType = NONE; break; case 3: if (win->key_cnt < 2) { fl_alert("set more keys first."); b->value(old_interp); return; } else { win->m_interpType = EM_SLERP; if (old_interp != win->m_interpType ) win->b_need_reinterp = true; } break; case 4: if (win->key_cnt < 2) { fl_alert("set more keys first."); b->value(old_interp); return; } else { win->m_interpType = EM_LIN; if (old_interp != win->m_interpType ) win->b_need_reinterp = true; } break; case 5: if (win->key_cnt < 4) { fl_alert("set more keys first."); b->value(old_interp); return; } else { win->m_interpType = CARDINAL; if (old_interp != win->m_interpType ) win->b_need_reinterp = true; } break; default: return; } if (old_interp != HIDE && old_interp != NONE && (win->m_interpType == NONE || win->m_interpType == HIDE) && win->m_rotType == EXPMAP) { // going from interp ->non-interp win->calc_markers_pos(win->marker_endsite, EXPMAP); if (win->marker_head != NULL) win->calc_markers_pos(win->marker_head, EXPMAP); } win->damage(1); } // sel camera view void camera_browserCB(Fl_Widget* wid, Fl_Widget *container) { Fl_Hold_Browser *b = (Fl_Hold_Browser *)wid; Gl_Win *win = (Gl_Win *)container; switch( b->value() ) { case OMIN: win->cameraView = OMIN; break; case FOLLOW: if ( win->cap == NULL ) { // no motion file loaded fl_alert("Load Motion file first."); b->value(OMIN); return; } else win->cameraView = FOLLOW; break; default: return; } win->damage(1); } // sel markers to be drawn void marker_sel_browserCB(Fl_Widget* wid, Fl_Widget *container) { Fl_Multi_Browser *b = (Fl_Multi_Browser *)wid; Gl_Win *win = (Gl_Win *)container; int cnt = b->size(); for (int i=1; i<=cnt; i++) { if (b->selected(i)) (win->endsites_draw)[i-1].b_draw = true; else (win->endsites_draw)[i-1].b_draw = false; } win->damage(1); }