- 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>
{ "-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" },
}
+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++)
counts[j].count++;
}
+ i = 0;
+ while (counts[i].atom) i++;
+ qsort (counts, i, sizeof(*counts), cmp_atoms);
+
i = 0;
while (counts[i].atom)
{
static void
gl_init (ModeInfo *mi)
{
- static GLfloat pos[4] = {5.0, 5.0, 10.0, 1.0};
+ 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};
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;