X-Git-Url: http://git.hungrycats.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=hacks%2Fglx%2Fmolecule.c;h=069d74752941308ebd95c56b6cd8a5cb96ef3320;hb=a1d41b2aa6e18bf9a49b914a99dda8232c5d7762;hp=447605c62dad08dd40289e9be9ba90bb5f393690;hpb=82c5080773aae5e72ec155327c075775e023d2ee;p=xscreensaver diff --git a/hacks/glx/molecule.c b/hacks/glx/molecule.c index 447605c6..069d7475 100644 --- a/hacks/glx/molecule.c +++ b/hacks/glx/molecule.c @@ -22,6 +22,49 @@ - 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 @@ -552,7 +595,8 @@ print_title_string (ModeInfo *mi, const char *string, y -= line_height; - glPushAttrib (GL_LIGHTING | GL_DEPTH_TEST); + glPushAttrib (GL_TRANSFORM_BIT | /* for matrix contents */ + GL_ENABLE_BIT); /* for various glDisable calls */ glDisable (GL_LIGHTING); glDisable (GL_DEPTH_TEST); { @@ -622,6 +666,21 @@ build_molecule (ModeInfo *mi) glEnable(GL_CULL_FACE); } +#if 0 + if (do_labels && !wire) + { + /* This is so all polygons are drawn slightly farther back in the depth + buffer, so that when we render text directly on top of the spheres, + it still shows up. */ + glEnable (GL_POLYGON_OFFSET_FILL); + glPolygonOffset (1.0, (do_bonds ? 10.0 : 35.0)); + } + else + { + glDisable (GL_POLYGON_OFFSET_FILL); + } +#endif + if (!wire) set_atom_color (mi, 0, False); @@ -659,55 +718,58 @@ build_molecule (ModeInfo *mi) } } - for (i = 0; i < m->natoms; i++) - { - molecule_atom *a = &m->atoms[i]; - int i; + if (!wire && do_atoms) + for (i = 0; i < m->natoms; i++) + { + 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); + } - if (!wire && do_atoms) - { - GLfloat size = atom_size (a); - set_atom_color (mi, a, False); - sphere (a->x, a->y, a->z, size, wire); - } + /* Second pass to draw labels, after all atoms and bonds are in place + */ + if (do_labels) + for (i = 0; i < m->natoms; i++) + { + molecule_atom *a = &m->atoms[i]; + int j; - if (do_labels) - { - glPushAttrib (GL_LIGHTING | GL_DEPTH_TEST); - glDisable (GL_LIGHTING); - glDisable (GL_DEPTH_TEST); + if (!wire) + { + glDisable (GL_LIGHTING); +#if 1 + glDisable (GL_DEPTH_TEST); +#endif + } - if (!wire) - set_atom_color (mi, a, True); + if (!wire) + set_atom_color (mi, a, True); - glRasterPos3f (a->x, a->y, a->z); + glRasterPos3f (a->x, a->y, a->z); - { - GLdouble mm[17], pm[17]; - GLint vp[5]; - GLdouble wx=-1, wy=-1, wz=-1; - glGetDoublev (GL_MODELVIEW_MATRIX, mm); - glGetDoublev (GL_PROJECTION_MATRIX, pm); - glGetIntegerv (GL_VIEWPORT, vp); - - /* Convert 3D coordinates to window coordinates */ - gluProject (a->x, a->y, a->z, mm, pm, vp, &wx, &wy, &wz); - - /* Fudge the window coordinates to center the string */ - wx -= string_width (mc->xfont1, a->label) / 2; - wy -= mc->xfont1->descent; - - /* Convert new window coordinates back to 3D coordinates */ - gluUnProject (wx, wy, wz, mm, pm, vp, &wx, &wy, &wz); - glRasterPos3f (wx, wy, wz); - } + /* Before drawing the string, shift the origin to center + the text over the origin of the sphere. */ + glBitmap (0, 0, 0, 0, + -string_width (mc->xfont1, a->label) / 2, + -mc->xfont1->descent, + NULL); - for (i = 0; i < strlen(a->label); i++) - glCallList (mc->font1_dlist + (int)(a->label[i])); + for (j = 0; j < strlen(a->label); j++) + glCallList (mc->font1_dlist + (int)(a->label[j])); - glPopAttrib(); - } - } + /* More efficient to always call glEnable() with correct values + than to call glPushAttrib()/glPopAttrib(), since reading + attributes from GL does a round-trip and stalls the pipeline. + */ + if (!wire) + { + glEnable(GL_LIGHTING); +#if 1 + glEnable(GL_DEPTH_TEST); +#endif + } + } if (do_bbox) draw_bounding_box (mi); @@ -1096,10 +1158,11 @@ reshape_molecule (ModeInfo *mi, int width, int height) glMatrixMode(GL_PROJECTION); glLoadIdentity(); - gluPerspective( 30.0, 1/h, 1.0, 100.0 ); + gluPerspective( 30.0, 1/h, 20.0, 40.0 ); gluLookAt( 0.0, 0.0, 15.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0); + glMatrixMode(GL_MODELVIEW); glLoadIdentity(); glTranslatef(0.0, 0.0, -15.0);