X-Git-Url: http://git.hungrycats.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=hacks%2Fglx%2Fmolecule.c;h=734fdd67e0b7abadba6137adc859573119f304a0;hb=bc7b7a8eb122206d239ec0e693676bcce31be1aa;hp=c54c101c6f6b821da0d2000de59bc25482e6a494;hpb=96bdd7cf6ea60c418a76921acaf0e34d6f5be930;p=xscreensaver diff --git a/hacks/glx/molecule.c b/hacks/glx/molecule.c index c54c101c..734fdd67 100644 --- a/hacks/glx/molecule.c +++ b/hacks/glx/molecule.c @@ -1,4 +1,4 @@ -/* molecule, Copyright (c) 2001 Jamie Zawinski +/* molecule, Copyright (c) 2001-2004 Jamie Zawinski * Draws molecules, based on coordinates from PDB (Protein Data Base) files. * * Permission to use, copy, modify, distribute, and sell this software and its @@ -18,6 +18,10 @@ http://www.sci.ouc.bc.ca/chem/molecule/molecule.html */ +#include +#include +#include +#include #include #define PROGCLASS "Molecule" @@ -37,11 +41,13 @@ #define DEF_BONDS "True" #define DEF_BBOX "False" #define DEF_MOLECULE "(default)" +#define DEF_VERBOSE "False" #define DEFAULTS "*delay: 10000 \n" \ "*timeout: " DEF_TIMEOUT "\n" \ "*showFPS: False \n" \ "*wireframe: False \n" \ + "*verbose: " DEF_VERBOSE "\n" \ "*molecule: " DEF_MOLECULE "\n" \ "*spin: " DEF_SPIN "\n" \ "*wander: " DEF_WANDER "\n" \ @@ -73,8 +79,8 @@ #include #include -#define SPHERE_SLICES 16 /* how densely to render spheres */ -#define SPHERE_STACKS 10 +#define SPHERE_SLICES 24 /* how densely to render spheres */ +#define SPHERE_STACKS 12 #define SMOOTH_TUBE /* whether to have smooth or faceted tubes */ @@ -90,6 +96,11 @@ static int scale_down; #define TUBE_FACES_2 3 +# ifdef __GNUC__ + __extension__ /* don't warn about "string length is greater than the length + ISO C89 compilers are required to support" when includng + the following data file... */ +# endif const char * const builtin_pdb_data[] = { # include "molecules.h" }; @@ -110,6 +121,7 @@ typedef struct { static atom_data all_atom_data[] = { { "H", 1.17, 0, "White", "Grey70", { 0, }}, { "C", 1.75, 0, "Grey60", "White", { 0, }}, + { "CA", 1.80, 0, "Blue", "LightBlue", { 0, }}, { "N", 1.55, 0, "LightSteelBlue3", "SlateBlue1", { 0, }}, { "O", 1.40, 0, "Red", "LightPink", { 0, }}, { "P", 1.28, 0, "MediumPurple", "PaleVioletRed", { 0, }}, @@ -156,6 +168,9 @@ typedef struct { int nmolecules; molecule *molecules; + int mode; /* 0 = normal, 1 = out, 2 = in */ + int mode_tick; + GLuint molecule_dlist; XFontStruct *xfont1, *xfont2; @@ -175,6 +190,7 @@ static Bool do_labels; static Bool do_atoms; static Bool do_bonds; static Bool do_bbox; +static Bool verbose_p; static Bool orig_do_labels, orig_do_bonds, orig_wire; /* saved to reset */ @@ -194,20 +210,22 @@ static XrmOptionDescRec opts[] = { { "+atoms", ".atoms", XrmoptionNoArg, "False" }, { "-bonds", ".bonds", XrmoptionNoArg, "True" }, { "+bonds", ".bonds", XrmoptionNoArg, "False" }, - { "-bbox", ".bbox", XrmoptionNoArg, "True" }, - { "+bbox", ".bbox", XrmoptionNoArg, "False" }, + { "-bbox", ".bbox", XrmoptionNoArg, "True" }, + { "+bbox", ".bbox", XrmoptionNoArg, "False" }, + { "-verbose",".verbose",XrmoptionNoArg, "True" }, }; static argtype vars[] = { - {(caddr_t *) &molecule_str, "molecule", "Molecule", DEF_MOLECULE,t_String}, - {(caddr_t *) &timeout, "timeout","Seconds",DEF_TIMEOUT,t_Int}, - {(caddr_t *) &do_spin, "spin", "Spin", DEF_SPIN, t_String}, - {(caddr_t *) &do_wander, "wander", "Wander", DEF_WANDER, t_Bool}, - {(caddr_t *) &do_labels, "labels", "Labels", DEF_LABELS, t_Bool}, - {(caddr_t *) &do_titles, "titles", "Titles", DEF_TITLES, t_Bool}, - {(caddr_t *) &do_atoms, "atoms", "Atoms", DEF_ATOMS, t_Bool}, - {(caddr_t *) &do_bonds, "bonds", "Bonds", DEF_BONDS, t_Bool}, - {(caddr_t *) &do_bbox, "bbox", "BBox", DEF_BBOX, t_Bool}, + {&molecule_str, "molecule", "Molecule", DEF_MOLECULE,t_String}, + {&timeout, "timeout","Seconds",DEF_TIMEOUT,t_Int}, + {&do_spin, "spin", "Spin", DEF_SPIN, t_String}, + {&do_wander, "wander", "Wander", DEF_WANDER, t_Bool}, + {&do_labels, "labels", "Labels", DEF_LABELS, t_Bool}, + {&do_titles, "titles", "Titles", DEF_TITLES, t_Bool}, + {&do_atoms, "atoms", "Atoms", DEF_ATOMS, t_Bool}, + {&do_bonds, "bonds", "Bonds", DEF_BONDS, t_Bool}, + {&do_bbox, "bbox", "BBox", DEF_BBOX, t_Bool}, + {&verbose_p, "verbose","Verbose",DEF_VERBOSE,t_Bool}, }; ModeSpecOpt molecule_opts = {countof(opts), opts, countof(vars), vars, NULL}; @@ -300,7 +318,7 @@ get_atom_data (const char *atom_name) for (i = 0; i < countof(all_atom_data); i++) { d = &all_atom_data[i]; - if (!strcmp (n, all_atom_data[i].name)) + if (!strcasecmp (n, all_atom_data[i].name)) break; } @@ -839,6 +857,12 @@ parse_pdb_data (molecule *m, const char *data, const char *filename, int line) ss = name + strlen(name)-1; while (isspace(*ss) && ss > name) *ss-- = 0; + ss = name + 1; + while(*ss) + { + *ss = tolower(*ss); + ss++; + } sscanf (s + 32, " %f %f %f ", &x, &y, &z); /* fprintf (stderr, "%s: %s: %d: atom: %d \"%s\" %9.4f %9.4f %9.4f\n", @@ -905,7 +929,7 @@ parse_pdb_data (molecule *m, const char *data, const char *filename, int line) } -static void +static int parse_pdb_file (molecule *m, const char *name) { FILE *in; @@ -919,7 +943,7 @@ parse_pdb_file (molecule *m, const char *name) char *buf = (char *) malloc(1024 + strlen(name)); sprintf(buf, "%s: error reading \"%s\"", progname, name); perror(buf); - exit (1); + return -1; } buf = (char *) malloc (buf_size); @@ -939,7 +963,7 @@ parse_pdb_file (molecule *m, const char *name) { fprintf (stderr, "%s: file %s contains no atomic coordinates!\n", progname, name); - exit (1); + return -1; } if (!m->nbonds && do_bonds) @@ -948,6 +972,8 @@ parse_pdb_file (molecule *m, const char *name) progname, name); do_bonds = 0; } + + return 0; } @@ -1067,41 +1093,136 @@ load_molecules (ModeInfo *mi) { molecule_configuration *mc = &mcs[MI_SCREEN(mi)]; int wire = MI_IS_WIREFRAME(mi); + int i; - if (!molecule_str || !*molecule_str || - !strcmp(molecule_str, "(default)")) /* do the builtins */ + mc->nmolecules = 0; + if (molecule_str && *molecule_str && + strcmp(molecule_str, "(default)")) /* try external PDB files */ + { + /* The -molecule option can point to a .pdb file, or to + a directory of them. + */ + struct stat st; + int nfiles = 0; + int list_size = 0; + char **files = 0; + int molecule_ctr; + + if (!stat (molecule_str, &st) && + S_ISDIR (st.st_mode)) + { + char buf [255]; + DIR *pdb_dir; + struct dirent *dentry; + + pdb_dir = opendir (molecule_str); + if (! pdb_dir) + { + sprintf (buf, "%.100s: %.100s", progname, molecule_str); + perror (buf); + exit (1); + } + + if (verbose_p) + fprintf (stderr, "%s: directory %s\n", progname, molecule_str); + + nfiles = 0; + list_size = 100; + files = (char **) calloc (sizeof(*files), list_size); + + while ((dentry = readdir (pdb_dir))) + { + int L = strlen (dentry->d_name); + if (L > 4 && !strcasecmp (dentry->d_name + L - 4, ".pdb")) + { + char *fn; + if (nfiles >= list_size-1) + { + list_size = (list_size + 10) * 1.2; + files = (char **) + realloc (files, list_size * sizeof(*files)); + if (!files) + { + OOM: + fprintf (stderr, "%s: out of memory (%d files)\n", + progname, nfiles); + exit (1); + } + } + + fn = (char *) malloc (strlen (molecule_str) + L + 10); + if (!fn) goto OOM; + strcpy (fn, molecule_str); + if (fn[strlen(fn)-1] != '/') strcat (fn, "/"); + strcat (fn, dentry->d_name); + files[nfiles++] = fn; + if (verbose_p) + fprintf (stderr, "%s: file %s\n", progname, fn); + } + } + closedir (pdb_dir); + + if (nfiles == 0) + fprintf (stderr, "%s: no .pdb files in directory %s\n", + progname, molecule_str); + } + else + { + files = (char **) malloc (sizeof (*files)); + nfiles = 1; + files[0] = strdup (molecule_str); + if (verbose_p) + fprintf (stderr, "%s: file %s\n", progname, molecule_str); + } + + mc->nmolecules = nfiles; + mc->molecules = (molecule *) calloc (sizeof (molecule), mc->nmolecules); + molecule_ctr = 0; + for (i = 0; i < mc->nmolecules; i++) + { + if (verbose_p) + fprintf (stderr, "%s: reading %s\n", progname, files[i]); + if (!parse_pdb_file (&mc->molecules[molecule_ctr], files[i])) + { + if ((wire || !do_atoms) && + !do_labels && + mc->molecules[molecule_ctr].nbonds == 0) + { + /* If we're not drawing atoms (e.g., wireframe mode), and + there is no bond info, then make sure labels are turned + on, or we'll be looking at a black screen... */ + fprintf (stderr, "%s: %s: no bonds: turning -label on.\n", + progname, files[i]); + do_labels = 1; + } + free (files[i]); + files[i] = 0; + molecule_ctr++; + } + } + + free (files); + files = 0; + mc->nmolecules = molecule_ctr; + } + + if (mc->nmolecules == 0) /* do the builtins if no files */ { - int i; mc->nmolecules = countof(builtin_pdb_data); mc->molecules = (molecule *) calloc (sizeof (molecule), mc->nmolecules); for (i = 0; i < mc->nmolecules; i++) { char name[100]; sprintf (name, "", i); + if (verbose_p) fprintf (stderr, "%s: reading %s\n", progname, name); parse_pdb_data (&mc->molecules[i], builtin_pdb_data[i], name, 1); - generate_molecule_formula (&mc->molecules[i]); - insert_vertical_whitespace ((char *) mc->molecules[i].label); } } - else /* Load a file */ + + for (i = 0; i < mc->nmolecules; i++) { - int i = 0; - mc->nmolecules = 1; - mc->molecules = (molecule *) calloc (sizeof (molecule), mc->nmolecules); - parse_pdb_file (&mc->molecules[i], molecule_str); generate_molecule_formula (&mc->molecules[i]); insert_vertical_whitespace ((char *) mc->molecules[i].label); - - if ((wire || !do_atoms) && - !do_labels && - mc->molecules[i].nbonds == 0) - { - /* If we're not drawing atoms (e.g., wireframe mode), and - there is no bond info, then make sure labels are turned on, - or we'll be looking at a black screen... */ - fprintf (stderr, "%s: no bonds: turning -label on.\n", progname); - do_labels = 1; - } } } @@ -1223,8 +1344,9 @@ init_molecule (ModeInfo *mi) { Bool spinx=False, spiny=False, spinz=False; - double spin_speed = 2.0; - double wander_speed = 0.03; + double spin_speed = 0.5; + double spin_accel = 0.3; + double wander_speed = 0.01; char *s = do_spin; while (*s) @@ -1245,7 +1367,7 @@ init_molecule (ModeInfo *mi) mc->rot = make_rotator (spinx ? spin_speed : 0, spiny ? spin_speed : 0, spinz ? spin_speed : 0, - 1.0, + spin_accel, do_wander ? wander_speed : 0, (spinx && spiny && spinz)); mc->trackball = gltrackball_init (); @@ -1260,6 +1382,7 @@ init_molecule (ModeInfo *mi) "NoLabelThreshold"); mc->wireframe_threshold = get_float_resource ("wireframeThreshold", "WireframeThreshold"); + mc->mode = 0; if (wire) do_bonds = 1; @@ -1354,11 +1477,63 @@ draw_labels (ModeInfo *mi) } +static void +pick_new_molecule (ModeInfo *mi, time_t last) +{ + molecule_configuration *mc = &mcs[MI_SCREEN(mi)]; + + if (mc->nmolecules == 1) + { + if (last != 0) return; + mc->which = 0; + } + else if (last == 0) + { + mc->which = random() % mc->nmolecules; + } + else + { + int n = mc->which; + while (n == mc->which) + n = random() % mc->nmolecules; + mc->which = n; + } + + if (verbose_p) + { + char *name = strdup (mc->molecules[mc->which].label); + char *s = strpbrk (name, "\r\n"); + if (s) *s = 0; + fprintf (stderr, "%s: drawing %s (%d)\n", progname, name, mc->which); + free (name); + } + + glNewList (mc->molecule_dlist, GL_COMPILE); + ensure_bounding_box_visible (mi); + + do_labels = orig_do_labels; + do_bonds = orig_do_bonds; + MI_IS_WIREFRAME(mi) = orig_wire; + + if (mc->molecule_size > mc->no_label_threshold) + do_labels = 0; + if (mc->molecule_size > mc->wireframe_threshold) + MI_IS_WIREFRAME(mi) = 1; + + if (MI_IS_WIREFRAME(mi)) + do_bonds = 1; + + build_molecule (mi); + glEndList(); +} + + void draw_molecule (ModeInfo *mi) { static time_t last = 0; time_t now = time ((time_t *) 0); + GLfloat speed = 4.0; /* speed at which the zoom out/in happens */ molecule_configuration *mc = &mcs[MI_SCREEN(mi)]; Display *dpy = MI_DISPLAY(mi); @@ -1367,48 +1542,48 @@ draw_molecule (ModeInfo *mi) if (!mc->glx_context) return; - if (last + timeout <= now && /* randomize molecules every -timeout seconds */ - !mc->button_down_p) + if (last == 0) { - if (mc->nmolecules == 1) - { - if (last != 0) goto SKIP; - mc->which = 0; - } - else if (last == 0) + pick_new_molecule (mi, last); + last = now; + } + else if (mc->mode == 0) + { + static int tick = 0; + if (tick++ > 10) { - mc->which = random() % mc->nmolecules; + time_t now = time((time_t *) 0); + if (last == 0) last = now; + tick = 0; + + if (!mc->button_down_p && + mc->nmolecules > 1 && + last + timeout <= now) + { + /* randomize molecules every -timeout seconds */ + mc->mode = 1; /* go out */ + mc->mode_tick = 10 * speed; + last = now; + } } - else + } + else if (mc->mode == 1) /* out */ + { + if (--mc->mode_tick <= 0) { - int n = mc->which; - while (n == mc->which) - n = random() % mc->nmolecules; - mc->which = n; + mc->mode_tick = 10 * speed; + mc->mode = 2; /* go in */ + pick_new_molecule (mi, last); + last = now; } - - last = now; - - - glNewList (mc->molecule_dlist, GL_COMPILE); - ensure_bounding_box_visible (mi); - - do_labels = orig_do_labels; - do_bonds = orig_do_bonds; - MI_IS_WIREFRAME(mi) = orig_wire; - - if (mc->molecule_size > mc->no_label_threshold) - do_labels = 0; - if (mc->molecule_size > mc->wireframe_threshold) - MI_IS_WIREFRAME(mi) = 1; - - if (MI_IS_WIREFRAME(mi)) - do_bonds = 1; - - build_molecule (mi); - glEndList(); } - SKIP: + else if (mc->mode == 2) /* in */ + { + if (--mc->mode_tick <= 0) + mc->mode = 0; /* normal */ + } + else + abort(); glPushMatrix (); glScalef(1.1, 1.1, 1.1); @@ -1429,8 +1604,19 @@ draw_molecule (ModeInfo *mi) } glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + + if (mc->mode != 0) + { + GLfloat s = (mc->mode == 1 + ? mc->mode_tick / (10 * speed) + : ((10 * speed) - mc->mode_tick + 1) / (10 * speed)); + glScalef (s, s, s); + } + glCallList (mc->molecule_dlist); - draw_labels (mi); + + if (mc->mode == 0) + draw_labels (mi); glPopMatrix ();