X-Git-Url: http://git.hungrycats.org/cgi-bin/gitweb.cgi?p=xscreensaver;a=blobdiff_plain;f=hacks%2Fglx%2Fmolecule.c;h=5178da62e0940a121ccf1db48fc03f249a039fdf;hp=734fdd67e0b7abadba6137adc859573119f304a0;hb=6b1c86cf395f59389e4ece4ea8f4bea2c332745b;hpb=bc7b7a8eb122206d239ec0e693676bcce31be1aa diff --git a/hacks/glx/molecule.c b/hacks/glx/molecule.c index 734fdd67..5178da62 100644 --- a/hacks/glx/molecule.c +++ b/hacks/glx/molecule.c @@ -1,4 +1,4 @@ -/* molecule, Copyright (c) 2001-2004 Jamie Zawinski +/* molecule, Copyright (c) 2001-2006 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 @@ -12,55 +12,25 @@ /* 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 -#include -#include -#include -#include - -#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_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" \ - "*labels: " DEF_LABELS "\n" \ - "*atoms: " DEF_ATOMS "\n" \ - "*bonds: " DEF_BONDS "\n" \ - "*bbox: " DEF_BBOX "\n" \ "*atomFont: -*-times-bold-r-normal-*-240-*\n" \ "*titleFont: -*-times-bold-r-normal-*-180-*\n" \ "*noLabelThreshold: 30 \n" \ "*wireframeThreshold: 150 \n" \ - +# define refresh_molecule 0 +# define release_molecule 0 #undef countof #define countof(x) (sizeof((x))/sizeof((*x))) @@ -68,16 +38,29 @@ #include "colors.h" #include "sphere.h" #include "tube.h" +#include "glxfonts.h" #include "rotator.h" #include "gltrackball.h" #ifdef USE_GL /* whole file */ -#include +#include +#include +#include #include -#include -#include -#include + +#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 @@ -90,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 @@ -118,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, }} }; @@ -135,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,9 +154,16 @@ typedef struct { int mode_tick; GLuint molecule_dlist; + GLuint shell_dlist; XFontStruct *xfont1, *xfont2; GLuint font1_dlist, font2_dlist; + int polygon_count; + + time_t draw_time; + int draw_tick; + + int scale_down; } molecule_configuration; @@ -189,90 +178,75 @@ static Bool do_titles; static Bool do_labels; static Bool do_atoms; static Bool do_bonds; +static Bool do_shells; static Bool do_bbox; static Bool verbose_p; +static GLfloat shell_alpha; -static Bool orig_do_labels, orig_do_bonds, orig_wire; /* saved to reset */ +/* saved to reset */ +static Bool orig_do_labels, orig_do_atoms, orig_do_bonds, orig_do_shells, + orig_wire; static XrmOptionDescRec opts[] = { - { "-molecule", ".molecule", XrmoptionSepArg, 0 }, - { "-timeout",".timeout",XrmoptionSepArg, 0 }, - { "-spin", ".spin", XrmoptionSepArg, 0 }, - { "+spin", ".spin", XrmoptionNoArg, "" }, - { "-wander", ".wander", XrmoptionNoArg, "True" }, - { "+wander", ".wander", XrmoptionNoArg, "False" }, - { "-labels", ".labels", XrmoptionNoArg, "True" }, - { "+labels", ".labels", XrmoptionNoArg, "False" }, - { "-titles", ".titles", XrmoptionNoArg, "True" }, - { "+titles", ".titles", XrmoptionNoArg, "False" }, - { "-atoms", ".atoms", XrmoptionNoArg, "True" }, - { "+atoms", ".atoms", XrmoptionNoArg, "False" }, - { "-bonds", ".bonds", XrmoptionNoArg, "True" }, - { "+bonds", ".bonds", XrmoptionNoArg, "False" }, - { "-bbox", ".bbox", XrmoptionNoArg, "True" }, - { "+bbox", ".bbox", XrmoptionNoArg, "False" }, - { "-verbose",".verbose",XrmoptionNoArg, "True" }, + { "-molecule", ".molecule", XrmoptionSepArg, 0 }, + { "-timeout", ".timeout", XrmoptionSepArg, 0 }, + { "-spin", ".spin", XrmoptionSepArg, 0 }, + { "+spin", ".spin", XrmoptionNoArg, "" }, + { "-wander", ".wander", XrmoptionNoArg, "True" }, + { "+wander", ".wander", XrmoptionNoArg, "False" }, + { "-labels", ".labels", XrmoptionNoArg, "True" }, + { "+labels", ".labels", XrmoptionNoArg, "False" }, + { "-titles", ".titles", XrmoptionNoArg, "True" }, + { "+titles", ".titles", XrmoptionNoArg, "False" }, + { "-atoms", ".atoms", XrmoptionNoArg, "True" }, + { "+atoms", ".atoms", XrmoptionNoArg, "False" }, + { "-bonds", ".bonds", XrmoptionNoArg, "True" }, + { "+bonds", ".bonds", XrmoptionNoArg, "False" }, + { "-shells", ".eshells", XrmoptionNoArg, "True" }, + { "+shells", ".eshells", XrmoptionNoArg, "False" }, + { "-shell-alpha", ".shellAlpha", XrmoptionSepArg, 0 }, + { "-bbox", ".bbox", XrmoptionNoArg, "True" }, + { "+bbox", ".bbox", XrmoptionNoArg, "False" }, + { "-verbose", ".verbose", XrmoptionNoArg, "True" }, }; static argtype vars[] = { - {&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}, + {&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_atoms, "atoms", "Atoms", DEF_ATOMS, t_Bool}, + {&do_bonds, "bonds", "Bonds", DEF_BONDS, t_Bool}, + {&do_shells, "eshells", "EShells", DEF_SHELLS, t_Bool}, + {&do_labels, "labels", "Labels", DEF_LABELS, t_Bool}, + {&do_titles, "titles", "Titles", DEF_TITLES, t_Bool}, + {&do_bbox, "bbox", "BBox", DEF_BBOX, t_Bool}, + {&shell_alpha, "shellAlpha", "ShellAlpha", DEF_SHELL_ALPHA, t_Float}, + {&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}; /* shapes */ -static void -sphere (GLfloat x, GLfloat y, GLfloat z, GLfloat diameter, Bool wire) +static int +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); glScalef (diameter, diameter, diameter); unit_sphere (stacks, slices, wire); glPopMatrix (); -} - -static void -load_font (ModeInfo *mi, char *res, XFontStruct **fontP, GLuint *dlistP) -{ - const char *font = get_string_resource (res, "Font"); - XFontStruct *f; - Font id; - int first, last; - - if (!font) font = "-*-times-bold-r-normal-*-180-*"; - - f = XLoadQueryFont(mi->dpy, font); - if (!f) f = XLoadQueryFont(mi->dpy, "fixed"); - - id = f->fid; - first = f->min_char_or_byte2; - last = f->max_char_or_byte2; - - clear_gl_error (); - *dlistP = glGenLists ((GLuint) last+1); - check_gl_error ("glGenLists"); - glXUseXFont(id, first, last-first+1, *dlistP + first); - check_gl_error ("glXUseXFont"); - - *fontP = f; + return stacks * slices; } @@ -280,32 +254,16 @@ static void load_fonts (ModeInfo *mi) { molecule_configuration *mc = &mcs[MI_SCREEN(mi)]; - load_font (mi, "atomFont", &mc->xfont1, &mc->font1_dlist); - load_font (mi, "titleFont", &mc->xfont2, &mc->font2_dlist); + load_font (mi->dpy, "atomFont", &mc->xfont1, &mc->font1_dlist); + load_font (mi->dpy, "titleFont", &mc->xfont2, &mc->font2_dlist); } -static int -string_width (XFontStruct *f, const char *c) -{ - int w = 0; - while (*c) - { - int cc = *((unsigned char *) c); - w += (f->per_char - ? f->per_char[cc-f->min_char_or_byte2].rbearing - : f->min_bounds.rbearing); - c++; - } - return w; -} - - -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; @@ -328,21 +286,31 @@ get_atom_data (const char *atom_name) static void -set_atom_color (ModeInfo *mi, molecule_atom *a, Bool font_p) +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) { @@ -358,36 +326,22 @@ set_atom_color (ModeInfo *mi, molecule_atom *a, Bool font_p) gl_color[0] = xcolor.red / 65536.0; gl_color[1] = xcolor.green / 65536.0; gl_color[2] = xcolor.blue / 65536.0; - gl_color[3] = 1.0; } + gl_color[3] = alpha; + if (font_p) - glColor3f (gl_color[0], gl_color[1], gl_color[2]); + glColor4f (gl_color[0], gl_color[1], gl_color[2], gl_color[3]); else glMaterialfv (GL_FRONT, GL_AMBIENT_AND_DIFFUSE, gl_color); } 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; } @@ -449,20 +403,20 @@ molecule_bounding_box (ModeInfo *mi, if (m->atoms[i].z > *z2) *z2 = m->atoms[i].z; } - *x1 -= 1; - *y1 -= 1; - *z1 -= 1; - *x2 += 1; - *y2 += 1; - *z2 += 1; + *x1 -= 1.5; + *y1 -= 1.5; + *z1 -= 1.5; + *x2 += 1.5; + *y2 += 1.5; + *z2 += 1.5; } static void draw_bounding_box (ModeInfo *mi) { - static GLfloat c1[4] = { 0.2, 0.2, 0.6, 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); @@ -543,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), @@ -559,85 +513,17 @@ ensure_bounding_box_visible (ModeInfo *mi) } -static void -print_title_string (ModeInfo *mi, const char *string, - GLfloat x, GLfloat y, XFontStruct *font) -{ - molecule_configuration *mc = &mcs[MI_SCREEN(mi)]; - GLfloat line_height = font->ascent + font->descent; - GLfloat sub_shift = (line_height * 0.3); - - y -= line_height; - - glPushAttrib (GL_TRANSFORM_BIT | /* for matrix contents */ - GL_ENABLE_BIT); /* for various glDisable calls */ - glDisable (GL_LIGHTING); - glDisable (GL_DEPTH_TEST); - { - glMatrixMode(GL_PROJECTION); - glPushMatrix(); - { - glLoadIdentity(); - - glMatrixMode(GL_MODELVIEW); - glPushMatrix(); - { - int i; - int x2 = x; - Bool sub_p = False; - glLoadIdentity(); - - gluOrtho2D (0, mi->xgwa.width, 0, mi->xgwa.height); - - set_atom_color (mi, 0, True); - - glRasterPos2f (x, y); - for (i = 0; i < strlen(string); i++) - { - char c = string[i]; - if (c == '\n') - { - glRasterPos2f (x, (y -= line_height)); - x2 = x; - } - else if (c == '(' && (isdigit (string[i+1]))) - { - sub_p = True; - glRasterPos2f (x2, (y -= sub_shift)); - } - else if (c == ')' && sub_p) - { - sub_p = False; - glRasterPos2f (x2, (y += sub_shift)); - } - else - { - glCallList (mc->font2_dlist + (int)(c)); - x2 += (font->per_char - ? font->per_char[c - font->min_char_or_byte2].width - : font->min_bounds.width); - } - } - } - glPopMatrix(); - } - glMatrixMode(GL_PROJECTION); - glPopMatrix(); - } - glPopAttrib(); - - glMatrixMode(GL_MODELVIEW); -} - /* Constructs the GL shapes of the current molecule */ static void -build_molecule (ModeInfo *mi) +build_molecule (ModeInfo *mi, Bool transparent_p) { molecule_configuration *mc = &mcs[MI_SCREEN(mi)]; int wire = MI_IS_WIREFRAME(mi); int i; + GLfloat alpha = transparent_p ? shell_alpha : 1.0; + int polys = 0; molecule *m = &mc->molecules[mc->which]; @@ -661,14 +547,14 @@ build_molecule (ModeInfo *mi) } if (!wire) - set_atom_color (mi, 0, False); + set_atom_color (mi, 0, False, alpha); 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) { @@ -676,10 +562,11 @@ build_molecule (ModeInfo *mi) glVertex3f(from->x, from->y, from->z); glVertex3f(to->x, to->y, to->z); glEnd(); + polys++; } 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 @@ -690,29 +577,29 @@ build_molecule (ModeInfo *mi) 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, False, wire); + 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); - sphere (a->x, a->y, a->z, size, wire); + set_atom_color (mi, a, False, alpha); + polys += sphere (mc, a->x, a->y, a->z, size, wire); } - if (do_bbox) - draw_bounding_box (mi); + if (do_bbox && !transparent_p) + { + draw_bounding_box (mi); + polys += 4; + } - if (do_titles && m->label && *m->label) - print_title_string (mi, m->label, - 10, mi->xgwa.height - 10, - mc->xfont2); + mc->polygon_count += polys; } @@ -766,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. */ @@ -836,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) || @@ -850,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++; @@ -863,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, @@ -877,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, @@ -1038,7 +947,7 @@ generate_molecule_formula (molecule *m) free (counts[i].atom); s += strlen (s); if (counts[i].count > 1) - sprintf (s, "(%d)", counts[i].count); + sprintf (s, "[%d]", counts[i].count); /* use [] to get subscripts */ s += strlen (s); i++; } @@ -1059,14 +968,14 @@ generate_molecule_formula (molecule *m) static void special_case_formula (char *f) { - if (!strcmp(f, "H(2)Be")) strcpy(f, "BeH(2)"); - else if (!strcmp(f, "H(3)B")) strcpy(f, "BH(3)"); - else if (!strcmp(f, "H(3)N")) strcpy(f, "NH(3)"); + if (!strcmp(f, "H[2]Be")) strcpy(f, "BeH[2]"); + else if (!strcmp(f, "H[3]B")) strcpy(f, "BH[3]"); + else if (!strcmp(f, "H[3]N")) strcpy(f, "NH[3]"); else if (!strcmp(f, "CHN")) strcpy(f, "HCN"); else if (!strcmp(f, "CKN")) strcpy(f, "KCN"); - else if (!strcmp(f, "H(4)N(2)")) strcpy(f, "N(2)H(4)"); - else if (!strcmp(f, "Cl(3)P")) strcpy(f, "PCl(3)"); - else if (!strcmp(f, "Cl(5)P")) strcpy(f, "PCl(5)"); + else if (!strcmp(f, "H[4]N[2]")) strcpy(f, "N[2]H[4]"); + else if (!strcmp(f, "Cl[3]P")) strcpy(f, "PCl[3]"); + else if (!strcmp(f, "Cl[5]P")) strcpy(f, "PCl[5]"); } @@ -1230,7 +1139,7 @@ load_molecules (ModeInfo *mi) /* Window management, etc */ -void +ENTRYPOINT void reshape_molecule (ModeInfo *mi, int width, int height) { GLfloat h = (GLfloat) height / (GLfloat) width; @@ -1239,7 +1148,7 @@ reshape_molecule (ModeInfo *mi, int width, int height) glMatrixMode(GL_PROJECTION); glLoadIdentity(); - gluPerspective (30.0, 1/h, 20.0, 40.0); + gluPerspective (30.0, 1/h, 20.0, 100.0); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); @@ -1254,18 +1163,14 @@ 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); glLightfv(GL_LIGHT0, GL_SPECULAR, spc); - - orig_do_labels = do_labels; - orig_do_bonds = do_bonds; - orig_wire = MI_IS_WIREFRAME(mi); } @@ -1274,21 +1179,21 @@ startup_blurb (ModeInfo *mi) { molecule_configuration *mc = &mcs[MI_SCREEN(mi)]; const char *s = "Constructing molecules..."; - print_title_string (mi, s, - mi->xgwa.width - (string_width (mc->xfont2, s) + 40), - 10 + mc->xfont2->ascent + mc->xfont2->descent, - mc->xfont2); + print_gl_string (mi->dpy, mc->xfont2, mc->font2_dlist, + mi->xgwa.width, mi->xgwa.height, + 10, mi->xgwa.height - 10, + s); glFinish(); glXSwapBuffers(MI_DISPLAY(mi), MI_WINDOW(mi)); } -Bool +ENTRYPOINT Bool molecule_handle_event (ModeInfo *mi, XEvent *event) { molecule_configuration *mc = &mcs[MI_SCREEN(mi)]; if (event->xany.type == ButtonPress && - event->xbutton.button & Button1) + event->xbutton.button == Button1) { mc->button_down_p = True; gltrackball_start (mc->trackball, @@ -1297,11 +1202,35 @@ molecule_handle_event (ModeInfo *mi, XEvent *event) return True; } else if (event->xany.type == ButtonRelease && - event->xbutton.button & Button1) + event->xbutton.button == Button1) { mc->button_down_p = False; return True; } + else if (event->xany.type == ButtonPress && + (event->xbutton.button == Button4 || + event->xbutton.button == Button5 || + event->xbutton.button == Button6 || + event->xbutton.button == Button7)) + { + gltrackball_mousewheel (mc->trackball, event->xbutton.button, 10, + !!event->xbutton.state); + return True; + } + else if (event->xany.type == KeyPress) + { + KeySym keysym; + char c = 0; + XLookupString (&event->xkey, &c, 1, &keysym, 0); + + if (c == ' ' || c == '\t' || c == '\r' || c == '\n') + { + GLfloat speed = 4.0; + mc->mode = 1; + mc->mode_tick = 10 * speed; + return True; + } + } else if (event->xany.type == MotionNotify && mc->button_down_p) { @@ -1315,7 +1244,7 @@ molecule_handle_event (ModeInfo *mi, XEvent *event) } -void +ENTRYPOINT void init_molecule (ModeInfo *mi) { molecule_configuration *mc; @@ -1354,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, @@ -1373,14 +1303,22 @@ init_molecule (ModeInfo *mi) mc->trackball = gltrackball_init (); } + orig_do_labels = do_labels; + orig_do_atoms = do_atoms; + orig_do_bonds = do_bonds; + orig_do_shells = do_shells; + orig_wire = MI_IS_WIREFRAME(mi); + mc->molecule_dlist = glGenLists(1); + if (do_shells) + mc->shell_dlist = glGenLists(1); 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; @@ -1393,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)]; @@ -1416,7 +1354,7 @@ draw_labels (ModeInfo *mi) glPushMatrix(); if (!wire) - set_atom_color (mi, a, True); + set_atom_color (mi, a, True, 1); /* First, we translate the origin to the center of the atom. @@ -1463,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(); @@ -1508,11 +1447,15 @@ pick_new_molecule (ModeInfo *mi, time_t last) free (name); } + mc->polygon_count = 0; + glNewList (mc->molecule_dlist, GL_COMPILE); ensure_bounding_box_visible (mi); do_labels = orig_do_labels; - do_bonds = orig_do_bonds; + do_atoms = orig_do_atoms; + do_bonds = orig_do_bonds; + do_shells = orig_do_shells; MI_IS_WIREFRAME(mi) = orig_wire; if (mc->molecule_size > mc->no_label_threshold) @@ -1521,17 +1464,43 @@ pick_new_molecule (ModeInfo *mi, time_t last) MI_IS_WIREFRAME(mi) = 1; if (MI_IS_WIREFRAME(mi)) - do_bonds = 1; + do_bonds = 1, do_shells = 0; - build_molecule (mi); + if (!do_bonds) + do_shells = 0; + + if (! (do_bonds || do_atoms || do_labels)) + { + /* Make sure *something* shows up! */ + MI_IS_WIREFRAME(mi) = 1; + do_bonds = 1; + } + + build_molecule (mi, False); glEndList(); + + if (do_shells) + { + glNewList (mc->shell_dlist, GL_COMPILE); + ensure_bounding_box_visible (mi); + + do_labels = 0; + do_atoms = 1; + do_bonds = 0; + + build_molecule (mi, True); + + glEndList(); + do_bonds = orig_do_bonds; + do_atoms = orig_do_atoms; + do_labels = orig_do_labels; + } } -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 */ @@ -1542,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; } } } @@ -1573,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 */ @@ -1613,17 +1583,56 @@ draw_molecule (ModeInfo *mi) glScalef (s, s, s); } + glPushMatrix(); glCallList (mc->molecule_dlist); if (mc->mode == 0) - draw_labels (mi); + { + molecule *m = &mc->molecules[mc->which]; + + draw_labels (mi); + + /* This can't go in the display list, or the characters are spaced + wrongly when the window is resized. */ + if (do_titles && m->label && *m->label) + { + set_atom_color (mi, 0, True, 1); + print_gl_string (mi->dpy, mc->xfont2, mc->font2_dlist, + mi->xgwa.width, mi->xgwa.height, + 10, mi->xgwa.height - 10, + m->label); + } + } + glPopMatrix(); + + if (do_shells) + { + glColorMask (GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); + glPushMatrix(); + glCallList (mc->shell_dlist); + glPopMatrix(); + glColorMask (GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); + + glDepthFunc (GL_EQUAL); + glEnable (GL_BLEND); + glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glPushMatrix(); + glCallList (mc->shell_dlist); + glPopMatrix(); + glDepthFunc (GL_LESS); + glDisable (GL_BLEND); + } glPopMatrix (); + mi->polygon_count = mc->polygon_count; + if (mi->fps_p) do_fps (mi); glFinish(); glXSwapBuffers(dpy, window); } +XSCREENSAVER_MODULE ("Molecule", molecule) + #endif /* USE_GL */