http://www.tienza.es/crux/src/www.jwz.org/xscreensaver/xscreensaver-5.05.tar.gz
[xscreensaver] / hacks / glx / molecule.c
index a787b0117445be7debcd0d59ce67488246c9aef4..5178da62e0940a121ccf1db48fc03f249a039fdf 100644 (file)
@@ -1,4 +1,4 @@
-/* molecule, Copyright (c) 2001-2005 Jamie Zawinski <jwz@jwz.org>
+/* molecule, Copyright (c) 2001-2006 Jamie Zawinski <jwz@jwz.org>
  * Draws molecules, based on coordinates from PDB (Protein Data Base) files.
  *
  * Permission to use, copy, modify, distribute, and sell this software and its
 
 
 /* Documentation on the PDB file format:
-   http://www.rcsb.org/pdb/docs/format/pdbguide2.2/guide2.2_frame.html
+   http://www.wwpdb.org/docs.html
+   http://www.rcsb.org/pdb/file_formats/pdb/pdbguide2.2/guide2.2_frame.html
 
    Good source of PDB files:
    http://www.sci.ouc.bc.ca/chem/molecule/molecule.html
+   http://www.umass.edu/microbio/rasmol/whereget.htm
+   http://www.wwpdb.org/docs.html
  */
 
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <unistd.h>
-#include <dirent.h>
-#include <X11/Intrinsic.h>
-
-#define PROGCLASS      "Molecule"
-#define HACK_INIT      init_molecule
-#define HACK_DRAW      draw_molecule
-#define HACK_RESHAPE   reshape_molecule
-#define HACK_HANDLE_EVENT molecule_handle_event
-#define EVENT_MASK     PointerMotionMask
-#define molecule_opts  xlockmore_opts
-
-#define DEF_TIMEOUT     "20"
-#define DEF_SPIN        "XYZ"
-#define DEF_WANDER      "False"
-#define DEF_LABELS      "True"
-#define DEF_TITLES      "True"
-#define DEF_ATOMS       "True"
-#define DEF_BONDS       "True"
-#define DEF_SHELLS      "False"
-#define DEF_BBOX        "False"
-#define DEF_SHELL_ALPHA "0.3"
-#define DEF_MOLECULE    "(default)"
-#define DEF_VERBOSE     "False"
-
 #define DEFAULTS       "*delay:        10000         \n" \
                        "*showFPS:      False         \n" \
                        "*wireframe:    False         \n" \
@@ -53,7 +29,8 @@
                        "*noLabelThreshold:    30     \n" \
                        "*wireframeThreshold:  150    \n" \
 
-
+# define refresh_molecule 0
+# define release_molecule 0
 #undef countof
 #define countof(x) (sizeof((x))/sizeof((*x)))
 
 
 #ifdef USE_GL /* whole file */
 
-#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <dirent.h>
 #include <ctype.h>
-#include <time.h>
-#include <sys/time.h>
-#include <GL/glu.h>
+
+#define DEF_TIMEOUT     "20"
+#define DEF_SPIN        "XYZ"
+#define DEF_WANDER      "False"
+#define DEF_LABELS      "True"
+#define DEF_TITLES      "True"
+#define DEF_ATOMS       "True"
+#define DEF_BONDS       "True"
+#define DEF_SHELLS      "True"
+#define DEF_BBOX        "False"
+#define DEF_SHELL_ALPHA "0.3"
+#define DEF_MOLECULE    "(default)"
+#define DEF_VERBOSE     "False"
 
 #define SPHERE_SLICES 24  /* how densely to render spheres */
 #define SPHERE_STACKS 12
@@ -84,7 +73,6 @@
 # define TUBE_FACES  8
 #endif
 
-static int scale_down;
 #define SPHERE_SLICES_2  7
 #define SPHERE_STACKS_2  4
 #define TUBE_FACES_2     3
@@ -112,16 +100,16 @@ typedef struct {
 /* These are the traditional colors used to render these atoms,
    and their approximate size in angstroms.
  */
-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, }},
-  { "S",    1.80,  0,  "Yellow4",         "Yellow1",       { 0, }},
-  { "bond", 0,     0,  "Grey70",          "Yellow1",       { 0, }},
-  { "*",    1.40,  0,  "Green4",          "LightGreen",    { 0, }}
+static const atom_data all_atom_data[] = {
+  { "H",    1.17,  0.40, "#FFFFFF", "#B3B3B3", { 0, }},
+  { "C",    1.75,  0.58, "#999999", "#FFFFFF", { 0, }},
+  { "CA",   1.80,  0.60, "#0000FF", "#ADD8E6", { 0, }},
+  { "N",    1.55,  0.52, "#A2B5CD", "#836FFF", { 0, }},
+  { "O",    1.40,  0.47, "#FF0000", "#FFB6C1", { 0, }},
+  { "P",    1.28,  0.43, "#9370DB", "#DB7093", { 0, }},
+  { "S",    1.80,  0.60, "#8B8B00", "#FFFF00", { 0, }},
+  { "bond", 0,     0,    "#B3B3B3", "#FFFF00", { 0, }},
+  { "*",    1.40,  0.47, "#008B00", "#90EE90", { 0, }}
 };
 
 
@@ -129,7 +117,7 @@ typedef struct {
   int id;              /* sequence number in the PDB file */
   const char *label;   /* The atom name */
   GLfloat x, y, z;     /* position in 3-space (angstroms) */
-  atom_data *data;     /* computed: which style of atom this is */
+  const atom_data *data; /* computed: which style of atom this is */
 } molecule_atom;
 
 typedef struct {
@@ -172,6 +160,11 @@ typedef struct {
   GLuint font1_dlist, font2_dlist;
   int polygon_count;
 
+  time_t draw_time;
+  int draw_tick;
+
+  int scale_down;
+
 } molecule_configuration;
 
 
@@ -233,7 +226,7 @@ static argtype vars[] = {
   {&verbose_p,   "verbose",    "Verbose",      DEF_VERBOSE,  t_Bool},
 };
 
-ModeSpecOpt molecule_opts = {countof(opts), opts, countof(vars), vars, NULL};
+ENTRYPOINT ModeSpecOpt molecule_opts = {countof(opts), opts, countof(vars), vars, NULL};
 
 
 
@@ -241,10 +234,11 @@ ModeSpecOpt molecule_opts = {countof(opts), opts, countof(vars), vars, NULL};
 /* shapes */
 
 static int
-sphere (GLfloat x, GLfloat y, GLfloat z, GLfloat diameter, Bool wire)
+sphere (molecule_configuration *mc,
+        GLfloat x, GLfloat y, GLfloat z, GLfloat diameter, Bool wire)
 {
-  int stacks = (scale_down ? SPHERE_STACKS_2 : SPHERE_STACKS);
-  int slices = (scale_down ? SPHERE_SLICES_2 : SPHERE_SLICES);
+  int stacks = (mc->scale_down ? SPHERE_STACKS_2 : SPHERE_STACKS);
+  int slices = (mc->scale_down ? SPHERE_SLICES_2 : SPHERE_SLICES);
 
   glPushMatrix ();
   glTranslatef (x, y, z);
@@ -265,11 +259,11 @@ load_fonts (ModeInfo *mi)
 }
 
 
-static atom_data *
+static const atom_data *
 get_atom_data (const char *atom_name)
 {
   int i;
-  atom_data *d = 0;
+  const atom_data *d = 0;
   char *n = strdup (atom_name);
   char *n2 = n;
   int L;
@@ -292,21 +286,31 @@ get_atom_data (const char *atom_name)
 
 
 static void
-set_atom_color (ModeInfo *mi, molecule_atom *a, Bool font_p, GLfloat alpha)
+set_atom_color (ModeInfo *mi, const molecule_atom *a, 
+                Bool font_p, GLfloat alpha)
 {
-  atom_data *d;
-  GLfloat *gl_color;
+  const atom_data *d;
+  GLfloat gl_color[4];
 
   if (a)
     d = a->data;
   else
+    d = get_atom_data ("bond");
+
+  if (font_p)
     {
-      static atom_data *def_data = 0;
-      if (!def_data) def_data = get_atom_data ("bond");
-      d = def_data;
+      gl_color[0] = d->gl_color[4];
+      gl_color[1] = d->gl_color[5];
+      gl_color[2] = d->gl_color[6];
+      gl_color[3] = d->gl_color[7];
+    }
+  else
+    {
+      gl_color[0] = d->gl_color[0];
+      gl_color[1] = d->gl_color[1];
+      gl_color[2] = d->gl_color[2];
+      gl_color[3] = d->gl_color[3];
     }
-
-  gl_color = (!font_p ? d->gl_color : (d->gl_color + 4));
 
   if (gl_color[3] == 0)
     {
@@ -334,25 +338,10 @@ set_atom_color (ModeInfo *mi, molecule_atom *a, Bool font_p, GLfloat alpha)
 
 
 static GLfloat
-atom_size (molecule_atom *a)
+atom_size (const molecule_atom *a)
 {
   if (do_bonds)
-    {
-      if (a->data->size2 == 0)
-        {
-          /* let the molecules have the same relative sizes, but scale
-             them to a smaller range, so that the bond-tubes are
-             actually visible...
-           */
-          GLfloat bot = 0.4;
-          GLfloat top = 0.6;
-          GLfloat min = 1.17;
-          GLfloat max = 1.80;
-          GLfloat ratio = (a->data->size - min) / (max - min);
-          a->data->size2 = bot + (ratio * (top - bot));
-        }
-      return a->data->size2;
-    }
+    return a->data->size2;
   else
     return a->data->size;
 }
@@ -426,8 +415,8 @@ molecule_bounding_box (ModeInfo *mi,
 static void
 draw_bounding_box (ModeInfo *mi)
 {
-  static GLfloat c1[4] = { 0.2, 0.2, 0.4, 1.0 };
-  static GLfloat c2[4] = { 1.0, 0.0, 0.0, 1.0 };
+  static const GLfloat c1[4] = { 0.2, 0.2, 0.4, 1.0 };
+  static const GLfloat c2[4] = { 1.0, 0.0, 0.0, 1.0 };
   int wire = MI_IS_WIREFRAME(mi);
   GLfloat x1, y1, z1, x2, y2, z2;
   molecule_bounding_box (mi, &x1, &y1, &z1, &x2, &y2, &z2);
@@ -508,14 +497,14 @@ ensure_bounding_box_visible (ModeInfo *mi)
 
   mc->molecule_size = size;
 
-  scale_down = 0;
+  mc->scale_down = 0;
 
   if (size > max_size)
     {
       GLfloat scale = max_size / size;
       glScalef (scale, scale, scale);
 
-      scale_down = scale < 0.3;
+      mc->scale_down = scale < 0.3;
     }
 
   glTranslatef (-(x1 + w/2),
@@ -563,9 +552,9 @@ build_molecule (ModeInfo *mi, Bool transparent_p)
   if (do_bonds)
     for (i = 0; i < m->nbonds; i++)
       {
-        molecule_bond *b = &m->bonds[i];
-        molecule_atom *from = get_atom (m->atoms, m->natoms, b->from);
-        molecule_atom *to   = get_atom (m->atoms, m->natoms, b->to);
+        const molecule_bond *b = &m->bonds[i];
+        const molecule_atom *from = get_atom (m->atoms, m->natoms, b->from);
+        const molecule_atom *to   = get_atom (m->atoms, m->natoms, b->to);
 
         if (wire)
           {
@@ -577,7 +566,7 @@ build_molecule (ModeInfo *mi, Bool transparent_p)
           }
         else
           {
-            int faces = (scale_down ? TUBE_FACES_2 : TUBE_FACES);
+            int faces = (mc->scale_down ? TUBE_FACES_2 : TUBE_FACES);
 # ifdef SMOOTH_TUBE
             int smooth = True;
 # else
@@ -588,21 +577,20 @@ build_molecule (ModeInfo *mi, Bool transparent_p)
             if (thickness > 0.3)
               thickness = 0.3;
 
-            tube (from->x, from->y, from->z,
-                  to->x,   to->y,   to->z,
-                  thickness, cap_size,
-                  faces, smooth, (!do_atoms || do_shells), wire);
-            polys += faces;
+            polys += tube (from->x, from->y, from->z,
+                           to->x,   to->y,   to->z,
+                           thickness, cap_size,
+                           faces, smooth, (!do_atoms || do_shells), wire);
           }
       }
 
   if (!wire && do_atoms)
     for (i = 0; i < m->natoms; i++)
       {
-        molecule_atom *a = &m->atoms[i];
+        const molecule_atom *a = &m->atoms[i];
         GLfloat size = atom_size (a);
         set_atom_color (mi, a, False, alpha);
-        polys += sphere (a->x, a->y, a->z, size, wire);
+        polys += sphere (mc, a->x, a->y, a->z, size, wire);
       }
 
   if (do_bbox && !transparent_p)
@@ -665,6 +653,14 @@ push_bond (molecule *m, int from, int to)
 }
 
 
+static void
+parse_error (const char *file, int lineno, const char *line)
+{
+  fprintf (stderr, "%s: %s: parse error, line %d: %s\n",
+           progname, file, lineno, line);
+  exit (1);
+}
+
 
 /* This function is crap.
  */
@@ -735,6 +731,15 @@ parse_pdb_data (molecule *m, const char *data, const char *filename, int line)
                !strncmp (s, "MTRIX3", 6) ||
                !strncmp (s, "SHEET ", 6) ||
                !strncmp (s, "CISPEP", 6) ||
+/*
+               !strncmp (s, "SEQADV", 6) ||
+               !strncmp (s, "SITE ",  5) ||
+               !strncmp (s, "FTNOTE", 6) ||
+               !strncmp (s, "MODEL ", 5) ||
+               !strncmp (s, "ENDMDL", 6) ||
+               !strncmp (s, "SPRSDE", 6) ||
+               !strncmp (s, "MODRES", 6) ||
+ */
                !strncmp (s, "GENERATED BY", 12) ||
                !strncmp (s, "TER ", 4) ||
                !strncmp (s, "END ", 4) ||
@@ -749,7 +754,8 @@ parse_pdb_data (molecule *m, const char *data, const char *filename, int line)
           char *name = (char *) calloc (1, 4);
           GLfloat x = -999, y = -999, z = -999;
 
-          sscanf (s+7, " %d ", &id);
+          if (1 != sscanf (s+7, " %d ", &id))
+            parse_error (filename, line, s);
 
           strncpy (name, s+12, 3);
           while (isspace(*name)) name++;
@@ -762,7 +768,9 @@ parse_pdb_data (molecule *m, const char *data, const char *filename, int line)
            *ss = tolower(*ss);
             ss++;
           }
-          sscanf (s + 32, " %f %f %f ", &x, &y, &z);
+          if (3 != sscanf (s + 32, " %f %f %f ", &x, &y, &z))
+            parse_error (filename, line, s);
+
 /*
           fprintf (stderr, "%s: %s: %d: atom: %d \"%s\" %9.4f %9.4f %9.4f\n",
                    progname, filename, line,
@@ -776,14 +784,16 @@ parse_pdb_data (molecule *m, const char *data, const char *filename, int line)
           char *name = (char *) calloc (1, 4);
           GLfloat x = -999, y = -999, z = -999;
 
-          sscanf (s+7, " %d ", &id);
+          if (1 != sscanf (s+7, " %d ", &id))
+            parse_error (filename, line, s);
 
           strncpy (name, s+12, 3);
           while (isspace(*name)) name++;
           ss = name + strlen(name)-1;
           while (isspace(*ss) && ss > name)
             *ss-- = 0;
-          sscanf (s + 30, " %f %f %f ", &x, &y, &z);
+          if (3 != sscanf (s + 30, " %f %f %f ", &x, &y, &z))
+            parse_error (filename, line, s);
 /*
           fprintf (stderr, "%s: %s: %d: atom: %d \"%s\" %9.4f %9.4f %9.4f\n",
                    progname, filename, line,
@@ -1129,7 +1139,7 @@ load_molecules (ModeInfo *mi)
 \f
 /* Window management, etc
  */
-void
+ENTRYPOINT void
 reshape_molecule (ModeInfo *mi, int width, int height)
 {
   GLfloat h = (GLfloat) height / (GLfloat) width;
@@ -1153,10 +1163,10 @@ reshape_molecule (ModeInfo *mi, int width, int height)
 static void
 gl_init (ModeInfo *mi)
 {
-  static GLfloat pos[4] = {1.0, 0.4, 0.9, 0.0};
-  static GLfloat amb[4] = {0.0, 0.0, 0.0, 1.0};
-  static GLfloat dif[4] = {0.8, 0.8, 0.8, 1.0};
-  static GLfloat spc[4] = {1.0, 1.0, 1.0, 1.0};
+  static const GLfloat pos[4] = {1.0, 0.4, 0.9, 0.0};
+  static const GLfloat amb[4] = {0.0, 0.0, 0.0, 1.0};
+  static const GLfloat dif[4] = {0.8, 0.8, 0.8, 1.0};
+  static const GLfloat spc[4] = {1.0, 1.0, 1.0, 1.0};
   glLightfv(GL_LIGHT0, GL_POSITION, pos);
   glLightfv(GL_LIGHT0, GL_AMBIENT,  amb);
   glLightfv(GL_LIGHT0, GL_DIFFUSE,  dif);
@@ -1177,7 +1187,7 @@ startup_blurb (ModeInfo *mi)
   glXSwapBuffers(MI_DISPLAY(mi), MI_WINDOW(mi));
 }
 
-Bool
+ENTRYPOINT Bool
 molecule_handle_event (ModeInfo *mi, XEvent *event)
 {
   molecule_configuration *mc = &mcs[MI_SCREEN(mi)];
@@ -1199,7 +1209,9 @@ molecule_handle_event (ModeInfo *mi, XEvent *event)
     }
   else if (event->xany.type == ButtonPress &&
            (event->xbutton.button == Button4 ||
-            event->xbutton.button == Button5))
+            event->xbutton.button == Button5 ||
+            event->xbutton.button == Button6 ||
+            event->xbutton.button == Button7))
     {
       gltrackball_mousewheel (mc->trackball, event->xbutton.button, 10,
                               !!event->xbutton.state);
@@ -1232,7 +1244,7 @@ molecule_handle_event (ModeInfo *mi, XEvent *event)
 }
 
 
-void 
+ENTRYPOINT void 
 init_molecule (ModeInfo *mi)
 {
   molecule_configuration *mc;
@@ -1271,6 +1283,7 @@ init_molecule (ModeInfo *mi)
         if      (*s == 'x' || *s == 'X') spinx = True;
         else if (*s == 'y' || *s == 'Y') spiny = True;
         else if (*s == 'z' || *s == 'Z') spinz = True;
+        else if (*s == '0') ;
         else
           {
             fprintf (stderr,
@@ -1303,9 +1316,9 @@ init_molecule (ModeInfo *mi)
   load_molecules (mi);
   mc->which = random() % mc->nmolecules;
 
-  mc->no_label_threshold = get_float_resource ("noLabelThreshold",
+  mc->no_label_threshold = get_float_resource (mi->dpy, "noLabelThreshold",
                                                "NoLabelThreshold");
-  mc->wireframe_threshold = get_float_resource ("wireframeThreshold",
+  mc->wireframe_threshold = get_float_resource (mi->dpy, "wireframeThreshold",
                                                 "WireframeThreshold");
   mc->mode = 0;
 
@@ -1318,7 +1331,7 @@ init_molecule (ModeInfo *mi)
    This can't be a part of the display list because of the games
    we play with the translation matrix.
  */
-void
+static void
 draw_labels (ModeInfo *mi)
 {
   molecule_configuration *mc = &mcs[MI_SCREEN(mi)];
@@ -1388,6 +1401,7 @@ draw_labels (ModeInfo *mi)
                 NULL);
 
       for (j = 0; j < strlen(a->label); j++)
+
         glCallList (mc->font1_dlist + (int)(a->label[j]));
 
       glPopMatrix();
@@ -1484,10 +1498,9 @@ pick_new_molecule (ModeInfo *mi, time_t last)
 }
 
 
-void
+ENTRYPOINT 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 */
 
@@ -1498,28 +1511,29 @@ draw_molecule (ModeInfo *mi)
   if (!mc->glx_context)
     return;
 
-  if (last == 0)
+  glXMakeCurrent(MI_DISPLAY(mi), MI_WINDOW(mi), *(mc->glx_context));
+
+  if (mc->draw_time == 0)
     {
-      pick_new_molecule (mi, last);
-      last = now;
+      pick_new_molecule (mi, mc->draw_time);
+      mc->draw_time = now;
     }
   else if (mc->mode == 0)
     {
-      static int tick = 0;
-      if (tick++ > 10)
+      if (mc->draw_tick++ > 10)
         {
           time_t now = time((time_t *) 0);
-          if (last == 0) last = now;
-          tick = 0;
+          if (mc->draw_time == 0) mc->draw_time = now;
+          mc->draw_tick = 0;
 
           if (!mc->button_down_p &&
               mc->nmolecules > 1 &&
-              last + timeout <= now)
+              mc->draw_time + timeout <= now)
             {
               /* randomize molecules every -timeout seconds */
               mc->mode = 1;    /* go out */
               mc->mode_tick = 10 * speed;
-              last = now;
+              mc->draw_time = now;
             }
         }
     }
@@ -1529,8 +1543,8 @@ draw_molecule (ModeInfo *mi)
         {
           mc->mode_tick = 10 * speed;
           mc->mode = 2;  /* go in */
-          pick_new_molecule (mi, last);
-          last = now;
+          pick_new_molecule (mi, mc->draw_time);
+          mc->draw_time = now;
         }
     }
   else if (mc->mode == 2)   /* in */
@@ -1619,4 +1633,6 @@ draw_molecule (ModeInfo *mi)
   glXSwapBuffers(dpy, window);
 }
 
+XSCREENSAVER_MODULE ("Molecule", molecule)
+
 #endif /* USE_GL */