#define PROG_NAME "dm_seq_view" #define PROG_DESC "3D interactive visualization of filtered DNA sequences" #define PROG_VERS "2.0" #define PROG_C_COPYRIGHT "Copyright � 2005 Universidade Estadual Fluminense (UFF)." /* Last edited on 2010-08-15 00:03:20 by stolfi */ #define PROG_HELP \ " " PROG_NAME " \\\n" \ " { -seqFile {DM_SEQ_FILE} }.." #define PROG_INFO \ "NAME\n" \ " " PROG_NAME " - " PROG_DESC "\n" \ "\n" \ "SYNOPSIS\n" \ PROG_HELP "\n" \ "\n" \ "DESCRIPTION\n" \ " Reads one or more filtered DNA sequences from files {DM_SEQ_FILE} and displays interactively in 3D\n" \ "\n" \ "OPTIONS\n" \ "\n" \ "DOCUMENTATION OPTIONS\n" \ argparser_help_info_HELP_INFO "\n" \ "\n" \ "AUTHOR\n" \ " Created 2012 by Rafael Saracchini, IC-Unicamp.\n" \ "\n" \ "MODIFICATION HISTORY\n" \ "\n" \ "WARRANTY\n" \ argparser_help_info_NO_WARRANTY "\n" \ "\n" \ "RIGHTS\n" \ " " PROG_C_COPYRIGHT ".\n" \ "\n" \ argparser_help_info_STANDARD_RIGHTS #define _GNU_SOURCE #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define INF INFINITY #define dmvw_debug_GL FALSE #define dmvw_debug_paint FALSE #define dmvw_zoom_step_ratio (15.0/16.0) /* Zoom in/out kbd commands multiply/divide the obs distance by this amount. */ #define dmvw_radius_scale_step_ratio (pow(2.0,1.0/12.0)) /* Scale incr/decr kbd commands multiply/divide the Z scale factor by this amount. */ /* COMMAND-LINE OPTIONS */ typedef struct options_t { string_vec_t seqFile; } options_t; /* GLOBAL VARIABLES USED BY GL METHODS */ typedef struct dmvw_state_t { /* Sequence list: */ dm_seq_t* seq; bool_t* draw_seq; int nseq; /* Drawing options*/ double radius; /*radius of dots.*/ bool_t perturbation; r3_t* prt_point; /* Current window dimensions (set by {dmvw_reshape_method}): */ GLint window_HSize; /* Width (mutable). */ GLint window_VSize; /* Height (mutable). */ /* Observer's position relative to center of bbox: */ GLfloat azimuth; /* Azimuth from X axis (degrees, mutable). */ GLfloat elevation; /* Elevation from XY plane (degrees, mutable). */ GLfloat distance; /* Distance (pixels, mutable). */ /* Mouse state: */ int mouse_x,mouse_y; /* Position of last mouse event (mutable). */ } dmvw_state_t; static dmvw_state_t *dmvw_state = NULL; /* The state displayed in the GL window. */ /* INTERNAL PROTOTYPES */ dmvw_state_t *dmvw_create_state(options_t *o); /* Creates and initializes a window data record, suitable for use used by the methods {dmvw_display_method} etc. */ dm_seq_t dmvw_read_seq(char *name); /* Reads a filtered DNA sequence from file {name}. */ options_t *dmvw_parse_options(int argc, char **argv); /* Parses the command line arguments and packs them as an {options_t}. */ int main(int argc,char** argv); /* MAJOR PAINTING FUNCTIONS */ void dmvw_paint_everything(dmvw_state_t *w); /* Repaints the sequences according to the data and parameters in {w}. */ void dmvw_set_perspective(dmvw_state_t *w); /* Sets the GL perspective view parameters according to the window size, observer position, and bounding box data stored in {w}. */ void dmvw_set_lights(dmvw_state_t *w); /* Sets the GL lighting parameters according to the state {w}. */ /* MEDIUM-LEVEL PAINTING */ /* GL WINDOW METHODS */ void dmvw_display_method(void); /* Processes redisplay requests by the window manager. */ void dmvw_reshape_method(int width, int height); /* Processes window reshape events. */ void dmvw_keyboard_method(unsigned char key, int x, int y); /* Processes keyboard events. */ void dmvw_passivemouse_method( int x, int y); /* Processes passive mouse events (no mouse clicked) */ void dmvw_activemouse_method( int x, int y); /* Processes active mouse events (mouse clicked) */ void dmvw_special_method(int key, int x, int y); /* Processes special user input events. */ /* IMPLEMENTATIONS */ int main(int argc, char** argv) { dmvw_GL_initialize_libraries(&argc, argv); options_t *o = dmvw_parse_options(argc, argv); dmvw_state = dmvw_create_state(o); dmvw_GL_initialize_window ( "Sequences", dmvw_display_method, dmvw_reshape_method, dmvw_keyboard_method, dmvw_passivemouse_method, dmvw_activemouse_method, dmvw_special_method ); dmvw_GL_start_viewing(); return 0; } dmvw_state_t *dmvw_create_state(options_t *o) { dmvw_state_t *w = (dmvw_state_t *)notnull(malloc(sizeof(dmvw_state_t)), "no mem"); w->window_HSize = dmvw_GL_default_window_HSize; w->window_VSize = dmvw_GL_default_window_VSize; /* Read height map, check and save the channel index: */ int i; w->nseq = o->seqFile.ne; w->seq = (dm_seq_t*) malloc(sizeof(dm_seq_t)*(o->seqFile.ne)); w->draw_seq = (bool_t*) malloc(sizeof(bool_t)*(o->seqFile.ne)); for(i =0 ; i < o->seqFile.ne; i++){ w->seq[i] = dmvw_read_seq(o->seqFile.e[i]); w->draw_seq[i] = TRUE; } w->radius = 0.01; w->perturbation = FALSE; w->prt_point = (r3_t*)malloc(sizeof(r3_t)*w->nseq); for(i = 0; i < w->nseq; i++){ w->prt_point[i] = (r3_t){{0,0,0}}; } /* Initial observer's position: */ w->azimuth = 0; w->elevation = 30; w->distance = 6.0; return w; } dm_seq_t dmvw_read_seq(char *name) { FILE* arq = open_read(name,TRUE); dm_seq_t seq = dm_seq_read(arq,1); fclose(arq); return seq; } void dmvw_paint_everything(dmvw_state_t *w) { /* Set the GL graphics modes for depth painting: */ glShadeModel(GL_SMOOTH); glDepthMask(GL_TRUE); glEnable(GL_DEPTH_TEST); /* Compute the center of attention: */ GLfloat ctrx = 0.0; GLfloat ctry = 0.0; GLfloat ctrz = 0.0; /* Compute observer's position: */ double az = M_PI*w->azimuth/180; /* Observer's azimuth in radians. */ double ev = M_PI*w->elevation/180; /* Observer's elevation in radians. */ double ca = cos(az), sa = sin(az); double ce = cos(ev), se = sin(ev); double R = w->distance; GLfloat obsx = ctrx + R * ca * ce; GLfloat obsy = ctry + R * sa * ce; GLfloat obsz = ctrz + R * se; glPushMatrix(); /* Set the view transformation matrix: */ gluLookAt( obsx, obsy, obsz, ctrx, ctry, ctrz, 0.0, 0.0, 1.0); /* Place the lights: */ dmvw_set_lights(w); /* Paint the sequences: */ int i; for(i = 0; i < w->nseq; i++){ if(w->draw_seq[i]){ frgb_t color = (frgb_t){{((double) i)/w->nseq, 1.0, 0.4}}; frgb_from_HTY_UV(&color); dm_view_tools_draw_sequence(&(w->seq[i]),&color,w->radius,w->prt_point[i]); } } /*Paint the tetrahedron*/ dm_view_tools_draw_tetrahedron(); glPopMatrix(); glDisable(GL_DEPTH_TEST); } void dmvw_set_perspective(dmvw_state_t *w) { /* Set viewport: */ glViewport(0, 0, (GLint)w->window_HSize, (GLint)w->window_VSize); /* Set perspective matrix: */ glMatrixMode(GL_PROJECTION); glLoadIdentity(); float angheight = 40.0; /* Angular height of window (degrees) */ float aspect = (float)w->window_HSize/(float)w->window_VSize; gluPerspective(angheight, aspect, 0.1, w->distance + 6.0); glMatrixMode(GL_MODELVIEW); } void dmvw_set_lights(dmvw_state_t *w) { glEnable(GL_LIGHTING); glEnable(GL_LIGHT0); double ambi = 0.1; /* Amount of ambient light. */ double spec = 0.0; /* Amount of shine-scatterable light. */ double diff = 1.0 - ambi - spec; /* Amount of diffusible light. */ if (ambi > 0) { GLfloat light_ambient[] = { ambi, ambi, ambi, 1.0 }; glLightfv(GL_LIGHT0, GL_AMBIENT, light_ambient); } if (diff > 0) { GLfloat light_diffuse[] = { diff, diff, diff, 1.0 }; glLightfv(GL_LIGHT0, GL_DIFFUSE, light_diffuse); } if (spec > 0) { GLfloat light_specular[] = { spec, spec, spec, 1.0 }; glLightfv(GL_LIGHT0, GL_SPECULAR, light_specular); } /* Choose light's position relative to observer: */ double rev = w->elevation/90.0; /* Observer's rel elevation, in {[-1_+1]}. */ double daz = +30; /* Azimuth rel to observer (degrees). */ double dev = rev*30; /* Elevation rel to observer (degrees). */ /* Compute light direction vector: */ double az = M_PI*(w->azimuth + daz)/180; /* Light's azimuth (radians). */ double ev = M_PI*(w->elevation + dev)/180; /* Observer's elevation (radians). */ double ca = cos(az), sa = sin(az); double ce = cos(ev), se = sin(ev); GLfloat dirx = ca * ce; GLfloat diry = sa * ce; GLfloat dirz = se; /* Place light at infinity: */ GLfloat pos[] = { dirx, diry, dirz, 0.0 }; glLightfv(GL_LIGHT0, GL_POSITION, pos); } /* GL EVENT-HANDLING METHODS */ void dmvw_display_method(void) { if (dmvw_debug_GL) { fprintf(stderr, "+ %s\n", __FUNCTION__); } dmvw_state_t *w = dmvw_state; /* Clear the window: */ glClearColor(0.750, 0.750, 0.750, 1.000); /* Light gray, opaque. */ glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT); /* Paint the terrain and stuff: */ dmvw_paint_everything(w); /* Display the result: */ glutSwapBuffers(); if (dmvw_debug_GL) { fprintf(stderr, "- %s\n", __FUNCTION__); } } void dmvw_reshape_method(int width, int height) { if (dmvw_debug_GL) { fprintf(stderr, "+ %s\n", __FUNCTION__); } dmvw_state_t *w = dmvw_state; /* Save window size: */ w->window_HSize = width; w->window_VSize = height; /* Adjust the perspective parameters to the window's current size: */ dmvw_set_perspective(w); if (dmvw_debug_GL) { fprintf(stderr, "- %s\n", __FUNCTION__); } } void dmvw_keyboard_method(unsigned char key, int x, int y) { if (dmvw_debug_GL) { fprintf(stderr, "+ %s\n", __FUNCTION__); } dmvw_state_t *w = dmvw_state; switch (key) { case 27: case 'q': case 'Q': /* Quit: */ exit(0); break; case 'Z': /* Zoom in, down to a limit: */ w->distance = fmax(w->distance*dmvw_zoom_step_ratio, 0.1); glutPostRedisplay(); break; case 'z': /* Zoom out, up to a limit: */ w->distance = fmin(w->distance/dmvw_zoom_step_ratio, 10); glutPostRedisplay(); break; case 'R': /* Increase dot and cylinder radius: */ w->radius *= dmvw_radius_scale_step_ratio; glutPostRedisplay(); break; case 'r': /* Decrease dot and cylinder radius: */ w->radius /= dmvw_radius_scale_step_ratio; glutPostRedisplay(); break; case 'p': case 'P': w->perturbation = !w->perturbation; { int i; if(w->perturbation) { srandom(time(NULL)); fprintf(stderr,"Togle pert TRUE\n"); } else{fprintf(stderr,"Togle pert FALSE\n");} for(i = 0; i < w->nseq; i++){ if(!w->perturbation){ w->prt_point[i] = (r3_t){{0,0,0}}; } else{ double rd0 = drandom()*w->radius*2; double rd1 = drandom()*w->radius*2; double rd2 = drandom()*w->radius*2; w->prt_point[i] = (r3_t){{rd0,rd1,rd2}}; } } } glutPostRedisplay(); break; case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': /* Select named channel of height map: */ { int i = key - '0'; if( i < w->nseq){ w->draw_seq[i] = !w->draw_seq[i]; } } glutPostRedisplay(); break; } if (dmvw_debug_GL) { fprintf(stderr, "- %s\n", __FUNCTION__); } } void dmvw_passivemouse_method( int x, int y) { dmvw_state_t *w = dmvw_state; w->mouse_x = x; w->mouse_y = y; } void dmvw_activemouse_method( int x, int y) { dmvw_state_t *w = dmvw_state; int xvec, yvec; xvec = w->mouse_x - x; yvec = w->mouse_y - y; float az = w->azimuth + xvec; float el = w->elevation - yvec; el = fmax(-88.0, fmin(+88.0, el)); w->elevation = el; w->azimuth = az; w->mouse_x = x; w->mouse_y = y; glutPostRedisplay(); } void dmvw_special_method(int key, int x, int y) { if (dmvw_debug_GL) { fprintf(stderr, "+ %s\n", __FUNCTION__); } dmvw_state_t *w = dmvw_state; switch (key) { case GLUT_KEY_UP: w->elevation = fmin(w->elevation + 2, +88.0); glutPostRedisplay(); break; case GLUT_KEY_DOWN: w->elevation = fmax(w->elevation - 2, -88.0); glutPostRedisplay(); break; case GLUT_KEY_LEFT: w->azimuth = w->azimuth + 2; glutPostRedisplay(); break; case GLUT_KEY_RIGHT: w->azimuth = w->azimuth - 2; glutPostRedisplay(); break; } if (dmvw_debug_GL) { fprintf(stderr, "- %s\n", __FUNCTION__); } } /* COMMAND LINE PARSING */ options_t *dmvw_parse_options(int argc, char **argv) { /* Initialize argument parser: */ argparser_t *pp = argparser_new(stderr, argc, argv); argparser_set_help(pp, PROG_NAME " version " PROG_VERS ", usage:\n" PROG_HELP); argparser_set_info(pp, PROG_INFO); argparser_process_help_info_options(pp); /* Allocate the program's option record: */ options_t *o = (options_t *)malloc(sizeof(options_t)); /* Parse the texture map name: */ int nseq = 0; o->seqFile = string_vec_new(10); while(argparser_keyword_present(pp,"-seqFile")){ string_vec_expand(&(o->seqFile),nseq); o->seqFile.e[nseq] = argparser_get_next(pp); nseq++; } string_vec_trim(&(o->seqFile),nseq); /* Check for spurious arguments: */ argparser_finish(pp); return o; }