http://packetstormsecurity.org/UNIX/admin/xscreensaver-4.01.tar.gz
[xscreensaver] / hacks / glx / molecule.c
index e9cc9852c237b64833770540e7d54412c7f79c29..02b8362461a5285bf26fd8661f602fb715da9085 100644 (file)
      - I'm not sure the text labels are being done in the best way;
        they are sometimes, but not always, occluded by spheres that
        pass in front of them. 
+
+   GENERAL OPENGL NAIVETY:
+
+       I don't understand the *right* way to place text in front of the
+       atoms.  What I'm doing now is close, but has glitches.  I think I
+       understand glPolygonOffset(), but I think it doesn't help me.
+
+       Here's how I'd phrase the problem I'm trying to solve:
+
+       - I have a bunch of spherical objects of various sizes
+       - I want a piece of text in the scene, between each object
+         and the observer
+       - the position of this text should be apparently tangential 
+         to the surface of the sphere, so that:
+         - it is never inside the sphere;
+         - but can be occluded by other objects in the scene.
+
+       So I was trying to use glPolygonOffset() to say "pretend all
+       polygons are N units deeper than they actually are" where N was
+       somewhere around the maximal radius of the objects.  Which wasn't a
+       perfect solution, but was close.  But it turns out that can't work,
+       because the second arg to glPolygonOffset() is multiplied by some
+       minimal depth quantum which is not revealed, so I can't pass it an
+       offset in scene units -- only in multiples of the quantum.  So I
+       don't know how many quanta in radius my spheres are.
+
+       I think I need to position and render the text with glRasterPos3f()
+       so that the text is influenced by the depth buffer.  If I used 2f,
+       or an explicit constant Z value, then the text would always be in
+       front of each sphere, and text would be visible for spheres that
+       were fully occluded, which isn't what I want.
+
+       So my only guess at this point is that I need to position the text
+       exactly where I want it, tangential to the spheres -- but that
+       means I need to be able to compute that XYZ position, which is
+       dependent on the position of the observer!  Which means two things:
+       first, while generating my scene, I need to take into account the
+       position of the observer, and I don't have a clue how to do that;
+       and second, it means I can't put my whole molecule in a display
+       list, because the XYZ position of the text in the scene changes at
+       every frame, as the molecule rotates.
+
+       This just *can't* be as hard as it seems!
  */
 
 #include <X11/Intrinsic.h>
 
 #ifdef USE_GL /* whole file */
 
+#include <stdlib.h>
 #include <ctype.h>
 #include <GL/glu.h>
 
@@ -186,7 +230,7 @@ static XrmOptionDescRec opts[] = {
   { "-molecule", ".molecule", XrmoptionSepArg, 0 },
   { "-timeout",".timeout",XrmoptionSepArg, 0 },
   { "-spin",   ".spin",   XrmoptionSepArg, 0 },
-  { "+spin",   ".spin",   XrmoptionNoArg, "" },
+  { "+spin",   ".spin",   XrmoptionNoArg, "False" },
   { "-wander", ".wander", XrmoptionNoArg, "True" },
   { "+wander", ".wander", XrmoptionNoArg, "False" },
   { "-labels", ".labels", XrmoptionNoArg, "True" },
@@ -991,13 +1035,34 @@ parse_pdb_file (molecule *m, const char *name)
 }
 
 
+typedef struct { char *atom; int count; } atom_and_count;
+
+/* When listing the components of a molecule, the convention is to put the
+   carbon atoms first, the hydrogen atoms second, and the other atom types
+   sorted alphabetically after that (although for some molecules, the usual
+   order is different, like for NH(3), but we don't special-case those.)
+ */
+static int
+cmp_atoms (const void *aa, const void *bb)
+{
+  const atom_and_count *a = (atom_and_count *) aa;
+  const atom_and_count *b = (atom_and_count *) bb;
+  if (!a->atom) return  1;
+  if (!b->atom) return -1;
+  if (!strcmp(a->atom, "C")) return -1;
+  if (!strcmp(b->atom, "C")) return  1;
+  if (!strcmp(a->atom, "H")) return -1;
+  if (!strcmp(b->atom, "H")) return  1;
+  return strcmp (a->atom, b->atom);
+}
+
 static void
 generate_molecule_formula (molecule *m)
 {
   char *buf = (char *) malloc (m->natoms * 10);
   char *s = buf;
   int i;
-  struct { char *atom; int count; } counts[200];
+  atom_and_count counts[200];
   memset (counts, 0, sizeof(counts));
   *s = 0;
   for (i = 0; i < m->natoms; i++)
@@ -1018,6 +1083,10 @@ generate_molecule_formula (molecule *m)
       counts[j].count++;
     }
 
+  i = 0;
+  while (counts[i].atom) i++;
+  qsort (counts, i, sizeof(*counts), cmp_atoms);
+
   i = 0;
   while (counts[i].atom)
     {