X-Git-Url: http://git.hungrycats.org/cgi-bin/gitweb.cgi?p=xscreensaver;a=blobdiff_plain;f=hacks%2Fglx%2Fpolyhedra-gl.c;h=cdc7888632ef4a05869ebd50ba1df5b307c7628e;hp=e85559dbe6b8ecf0613aa03345073954a0e16cfb;hb=ffd8c0873576a9e3065696a624dce6b766b77062;hpb=9c9d475ff889ed8be02e8ce8c17da28b93278fca diff --git a/hacks/glx/polyhedra-gl.c b/hacks/glx/polyhedra-gl.c index e85559db..cdc78886 100644 --- a/hacks/glx/polyhedra-gl.c +++ b/hacks/glx/polyhedra-gl.c @@ -13,12 +13,6 @@ * * This file contains the OpenGL side; computation of the polyhedra themselves * is in "polyhedra.c". - * - * KNOWN BUG: - * - * The normals are wrong (inverted) on some faces of some of the duals - * (e.g., "Rhombicosacron".) I can't figure out how to tell when the - * normal should be pointing the other way. */ #include @@ -57,6 +51,8 @@ extern XtAppContext app; #define countof(x) (sizeof((x))/sizeof((*x))) #include "xlockmore.h" +#include + #include "polyhedra.h" #include "colors.h" #include "rotator.h" @@ -173,35 +169,39 @@ calc_normal (XYZ p, XYZ p1, XYZ p2) } +/* Calculate the normals at each vertex of a face, and use the sum to + decide which normal to assign to the entire face. This also solves + problems caused by nonconvex faces, in most (but not all) cases. + */ static void -do_normal(GLfloat x1, GLfloat y1, GLfloat z1, - GLfloat x2, GLfloat y2, GLfloat z2, - GLfloat x3, GLfloat y3, GLfloat z3) +kludge_normal (int n, const int *indices, const point *points) { - XYZ p1, p2, p3, p; - p1.x = x1; p1.y = y1; p1.z = z1; - p2.x = x2; p2.y = y2; p2.z = z2; - p3.x = x3; p3.y = y3; p3.z = z3; + XYZ normal = { 0, 0, 0 }; + XYZ p; + int i; - p = calc_normal (p1, p2, p3); + for (i = 0; i < n; ++i) { + int i1 = indices[i]; + int i2 = indices[(i + 1) % n]; + int i3 = indices[(i + 2) % n]; + XYZ p1, p2, p3; - glNormal3f (p.x, p.y, p.z); + p1.x = points[i1].x; p1.y = points[i1].y; p1.z = points[i1].z; + p2.x = points[i2].x; p2.y = points[i2].y; p2.z = points[i2].z; + p3.x = points[i3].x; p3.y = points[i3].y; p3.z = points[i3].z; -#ifdef DEBUG - /* Draw a line in the direction of this face's normal. */ - { - glPushMatrix(); - glTranslatef ((x1 + x2 + x3) / 3, - (y1 + y2 + y3) / 3, - (z1 + z2 + z3) / 3); - glScalef (0.5, 0.5, 0.5); - glBegin(GL_LINE_LOOP); - glVertex3f(0, 0, 0); - glVertex3f(p.x, p.y, p.z); - glEnd(); - glPopMatrix(); + p = calc_normal (p1, p2, p3); + normal.x += p.x; + normal.y += p.y; + normal.z += p.z; + } + + normalize(&normal); + if (normal.x == 0 && normal.y == 0 && normal.z == 0) { + glNormal3f (p.x, p.y, p.z); + } else { + glNormal3f (normal.x, normal.y, normal.z); } -#endif /* DEBUG */ } static void @@ -481,6 +481,14 @@ new_label (ModeInfo *mi) } +static void +tess_error (GLenum errorCode) +{ + fprintf (stderr, "%s: tesselation error: %s\n", + progname, gluErrorString(errorCode)); + exit (0); +} + static void new_polyhedron (ModeInfo *mi) { @@ -490,6 +498,15 @@ new_polyhedron (ModeInfo *mi) static GLfloat bcolor[4] = {0.0, 0.0, 0.0, 1.0}; int i; + /* Use the GLU polygon tesselator so that nonconvex faces are displayed + correctly (e.g., for the "pentagrammic concave deltohedron"). + */ + GLUtesselator *tobj = gluNewTess(); + gluTessCallback (tobj, GLU_TESS_BEGIN, (_GLUfuncptr) &glBegin); + gluTessCallback (tobj, GLU_TESS_END, (_GLUfuncptr) &glEnd); + gluTessCallback (tobj, GLU_TESS_VERTEX, (_GLUfuncptr) &glVertex3dv); + gluTessCallback (tobj, GLU_TESS_ERROR, (_GLUfuncptr) &tess_error); + mi->polygon_count = 0; bp->ncolors = 128; @@ -526,30 +543,22 @@ new_polyhedron (ModeInfo *mi) glMaterialfv (GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, bcolor); } - do_normal (p->points[f->points[0]].x, - p->points[f->points[0]].y, - p->points[f->points[0]].z, - p->points[f->points[1]].x, - p->points[f->points[1]].y, - p->points[f->points[1]].z, - p->points[f->points[2]].x, - p->points[f->points[2]].y, - p->points[f->points[2]].z); - - glBegin (wire ? GL_LINE_LOOP : - f->npoints == 3 ? GL_TRIANGLES : - f->npoints == 4 ? GL_QUADS : - GL_POLYGON); + kludge_normal (f->npoints, f->points, p->points); + + gluTessBeginPolygon (tobj, 0); + gluTessBeginContour (tobj); for (j = 0; j < f->npoints; j++) { point *pp = &p->points[f->points[j]]; - glVertex3f (pp->x, pp->y, pp->z); + gluTessVertex (tobj, &pp->x, &pp->x); } - glEnd(); + gluTessEndContour (tobj); + gluTessEndPolygon (tobj); } glEndList (); mi->polygon_count += p->nfaces; + gluDeleteTess (tobj); } @@ -592,6 +601,11 @@ init_polyhedra (ModeInfo *mi) glEnable(GL_DEPTH_TEST); /* glEnable(GL_CULL_FACE); */ + /* We need two-sided lighting for polyhedra where both sides of + a face are simultaneously visible (e.g., the "X-hemi-Y-hedrons".) + */ + glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_TRUE); + glLightfv(GL_LIGHT0, GL_POSITION, pos); glLightfv(GL_LIGHT0, GL_AMBIENT, amb); glLightfv(GL_LIGHT0, GL_DIFFUSE, dif);