From http://www.jwz.org/xscreensaver/xscreensaver-5.37.tar.gz
[xscreensaver] / hacks / glx / morph3d.c
index 99316b0768d119d7e8a17377d803a29f53451b2c..4bea5766f90002f2545eb7a9dd62b7a5d1c87e07 100644 (file)
@@ -1,21 +1,31 @@
-#if !defined( lint ) && !defined( SABER )
-static const char sccsid[] = "@(#)morph3d.c    4.02 97/04/01 xlockmore";
+/* -*- Mode: C; tab-width: 4 -*- */
+/* morph3d --- Shows 3D morphing objects */
 
+#if 0
+static const char sccsid[] = "@(#)morph3d.c    5.01 2001/03/01 xlockmore";
 #endif
 
 #undef DEBUG_CULL_FACE
 
 /*-
- * morph3d.c - Shows 3D morphing objects (XLock Version)
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation for any purpose and without fee is hereby granted,
+ * provided that the above copyright notice appear in all copies and that
+ * both that copyright notice and this permission notice appear in
+ * supporting documentation.
  *
- * See xlock.c for copying information.
+ * This file is provided AS IS with no warranties of any kind.  The author
+ * shall have no liability with respect to the infringement of copyrights,
+ * trade secrets or any patents by this file or any part thereof.  In no
+ * event will the author be liable for any lost revenue or profits or
+ * other special, indirect and consequential damages.
  *
- * The original code for this mode was written by Marcelo Fernandes Vianna 
- * (me...) and was inspired on a WindowsNT(R)'s screen saver. It was written 
- * from scratch and it was not based on any other source code. 
- * 
- * Porting it to xlock (the final objective of this code since the moment I 
- * decided to create it) was possible by comparing the original Mesa's gear 
+ * The original code for this mode was written by Marcelo Fernandes Vianna
+ * (me...) and was inspired on a WindowsNT(R)'s screen saver (Flower Box).
+ * It was written from scratch and it was not based on any other source code.
+ *
+ * Porting it to xlock (the final objective of this code since the moment I
+ * decided to create it) was possible by comparing the original Mesa's gear
  * demo with it's ported version to xlock, so thanks for Danny Sung (look at
  * gear.c) for his indirect help.
  *
@@ -25,51 +35,50 @@ static const char sccsid[] = "@(#)morph3d.c 4.02 97/04/01 xlockmore";
  * If you are interested in the original version of this program (not a xlock
  * mode, please refer to the Mesa package (ftp iris.ssec.wisc.edu on /pub/Mesa)
  *
- * Since I'm not a native english speaker, my apologies for any gramatical
- * mistake.
+ * Since I'm not a native English speaker, my apologies for any grammatical
+ * mistakes.
  *
- * My e-mail addresses are
- * vianna@cat.cbpf.br 
- *         and
- * marcelo@venus.rdc.puc-rio.br
+ * My e-mail address is
+ * mfvianna@centroin.com.br
  *
  * Marcelo F. Vianna (Feb-13-1997)
  *
  * Revision History:
- * 27-Jul-97: Speed ups by Marcelo F. Vianna.
- * 08-May-97: Speed ups by Marcelo F. Vianna.
+ * 05-Apr-2002: Removed all gllist uses (fix some bug with nvidia driver)
+ * 01-Mar-2001: Added FPS stuff E.Lassauge <lassauge@mail.dotcom.fr>
+ * 27-Jul-1997: Speed ups by Marcelo F. Vianna.
+ * 08-May-1997: Speed ups by Marcelo F. Vianna.
  *
  */
 
-/*-
- * PURIFY 3.0a on SunOS4 reports an unitialized memory read on each of
- * the glCallList() functions below when using MesaGL 2.1.  This has
- * been fixed in MesaGL 2.2 and later releases.
- */
-
-/*-
- * due to a Bug/feature in VMS X11/Intrinsic.h has to be placed before xlock.
- * otherwise caddr_t is not defined correctly
- */
-
-#include <X11/Intrinsic.h>
-
 #ifdef STANDALONE
-# define PROGCLASS             "Morph3d"
-# define HACK_INIT             init_morph3d
-# define HACK_DRAW             draw_morph3d
-# define morph3d_opts          xlockmore_opts
-# define DEFAULTS              "*delay: 1000 \n" \
-                               "*count: 0 \n"
+# define MODE_moebius
+# define DEFAULTS              "*delay:                40000   \n"             \
+                                               "*showFPS:      False   \n"             \
+                                               "*count:                0               \n"             \
+                                               "*suppressRotationAnimation: True\n" \
+
+# define refresh_morph3d 0
+# define release_morph3d 0
+# define morph3d_handle_event 0
 # include "xlockmore.h"                /* from the xscreensaver distribution */
 #else /* !STANDALONE */
 # include "xlock.h"            /* from the xlockmore distribution */
 #endif /* !STANDALONE */
 
-#ifdef USE_GL
+#ifdef MODE_moebius
+
+ENTRYPOINT ModeSpecOpt morph3d_opts =
+{0, (XrmOptionDescRec *) NULL, 0, (argtype *) NULL, (OptionStruct *) NULL};
 
-ModeSpecOpt morph3d_opts =
-{0, NULL, 0, NULL, NULL};
+#ifdef USE_MODULES
+ModStruct   morph3d_description =
+{"morph3d", "init_morph3d", "draw_morph3d", (char *) NULL,
+ "draw_morph3d", "change_morph3d", (char *) NULL, &morph3d_opts,
+ 1000, 0, 1, 1, 4, 1.0, "",
+ "Shows GL morphing polyhedra", 0, NULL};
+
+#endif
 
 #define Scale4Window               0.3
 #define Scale4Iconic               1.0
@@ -115,49 +124,35 @@ typedef struct {
        int         VisibleSpikes;
        void        (*draw_object) (ModeInfo * mi);
        float       Magnitude;
-       float      *MaterialColor[20];
-       GLXContext  glx_context;
+       const float *MaterialColor[20];
+       GLXContext *glx_context;
+    int         arrayninit;
+
 } morph3dstruct;
 
-static float front_shininess[] =
-{60.0};
-static float front_specular[] =
-{0.7, 0.7, 0.7, 1.0};
-static float ambient[] =
-{0.0, 0.0, 0.0, 1.0};
-static float diffuse[] =
-{1.0, 1.0, 1.0, 1.0};
-static float position0[] =
-{1.0, 1.0, 1.0, 0.0};
-static float position1[] =
-{-1.0, -1.0, 1.0, 0.0};
-static float lmodel_ambient[] =
-{0.5, 0.5, 0.5, 1.0};
-static float lmodel_twoside[] =
-{GL_TRUE};
-
-static float MaterialRed[] =
-{0.7, 0.0, 0.0, 1.0};
-static float MaterialGreen[] =
-{0.1, 0.5, 0.2, 1.0};
-static float MaterialBlue[] =
-{0.0, 0.0, 0.7, 1.0};
-static float MaterialCyan[] =
-{0.2, 0.5, 0.7, 1.0};
-static float MaterialYellow[] =
-{0.7, 0.7, 0.0, 1.0};
-static float MaterialMagenta[] =
-{0.6, 0.2, 0.5, 1.0};
-static float MaterialWhite[] =
-{0.7, 0.7, 0.7, 1.0};
-static float MaterialGray[] =
-{0.2, 0.2, 0.2, 1.0};
-
-static morph3dstruct *morph3d = NULL;
+static const GLfloat front_shininess[] = {60.0};
+static const GLfloat front_specular[]  = {0.7, 0.7, 0.7, 1.0};
+static const GLfloat ambient[]         = {0.0, 0.0, 0.0, 1.0};
+static const GLfloat diffuse[]         = {1.0, 1.0, 1.0, 1.0};
+static const GLfloat position0[]       = {1.0, 1.0, 1.0, 0.0};
+static const GLfloat position1[]       = {-1.0, -1.0, 1.0, 0.0};
+static const GLfloat lmodel_ambient[]  = {0.5, 0.5, 0.5, 1.0};
+static const GLfloat lmodel_twoside[]  = {GL_TRUE};
+
+static const GLfloat MaterialRed[]     = {0.7, 0.0, 0.0, 1.0};
+static const GLfloat MaterialGreen[]   = {0.1, 0.5, 0.2, 1.0};
+static const GLfloat MaterialBlue[]    = {0.0, 0.0, 0.7, 1.0};
+static const GLfloat MaterialCyan[]    = {0.2, 0.5, 0.7, 1.0};
+static const GLfloat MaterialYellow[]  = {0.7, 0.7, 0.0, 1.0};
+static const GLfloat MaterialMagenta[] = {0.6, 0.2, 0.5, 1.0};
+static const GLfloat MaterialWhite[]   = {0.7, 0.7, 0.7, 1.0};
+static const GLfloat MaterialGray[]    = {0.5, 0.5, 0.5, 1.0};
+
+static morph3dstruct *morph3d = (morph3dstruct *) NULL;
 
 #define TRIANGLE(Edge, Amp, Divisions, Z, VS)                                                                    \
 {                                                                                                                \
-  GLfloat   Xf,Yf,Xa,Yb,Xf2,Yf2,Yf_2,Yb2,Yb_2;                                                                   \
+  GLfloat   Xf,Yf,Xa,Yb=0.0,Xf2=0.0,Yf2=0.0,Yf_2=0.0,Yb2,Yb_2;                                                   \
   GLfloat   Factor=0.0,Factor1,Factor2;                                                                          \
   GLfloat   VertX,VertY,VertZ,NeiAX,NeiAY,NeiAZ,NeiBX,NeiBY,NeiBZ;                                               \
   GLfloat   Ax,Ay;                                                                                               \
@@ -183,6 +178,7 @@ static morph3dstruct *morph3d = NULL;
       NeiBX=Factor2*Xf-VertX; NeiBY=Factor2*Yb-VertY; NeiBZ=Factor2*Zf-VertZ;                                    \
       glNormal3f(VectMul(NeiAX, NeiAY, NeiAZ, NeiBX, NeiBY, NeiBZ));                                             \
       glVertex3f(VertX, VertY, VertZ);                                                                           \
+      mi->polygon_count++;                                                                                       \
                                                                                                                  \
       Xf-=Ax; Yf-=Ay; Xa-=Ax; Yb-=Ay;                                                                            \
                                                                                                                  \
@@ -194,6 +190,7 @@ static morph3dstruct *morph3d = NULL;
       NeiBX=Factor2*Xf-VertX; NeiBY=Factor2*Yb-VertY; NeiBZ=Factor2*Zf-VertZ;                                    \
       glNormal3f(VectMul(NeiAX, NeiAY, NeiAZ, NeiBX, NeiBY, NeiBZ));                                             \
       glVertex3f(VertX, VertY, VertZ);                                                                           \
+      mi->polygon_count++;                                                                                       \
                                                                                                                  \
       Xf-=Ax; Yf+=Ay; Xa-=Ax; Yb+=Ay;                                                                            \
     }                                                                                                            \
@@ -249,6 +246,7 @@ static morph3dstruct *morph3d = NULL;
       NeiBX=Factor2*Xf-VertX; NeiBY=Factor2*Yb-VertY; NeiBZ=Factor2*Zf-VertZ;                                    \
       glNormal3f(VectMul(NeiAX, NeiAY, NeiAZ, NeiBX, NeiBY, NeiBZ));                                             \
       glVertex3f(VertX, VertY, VertZ);                                                                           \
+      mi->polygon_count++;                                                                                       \
     }                                                                                                            \
     glEnd();                                                                                                     \
   }                                                                                                              \
@@ -264,15 +262,11 @@ static morph3dstruct *morph3d = NULL;
   GLfloat   Zf=(Edge)*(Z);                                                                                       \
   GLfloat   AmpVr2=(Amp)/sqr((Edge)*cossec36_2);                                                                 \
                                                                                                                  \
-  static    GLfloat x[6],y[6];                                                                                   \
-  static    arrayninit=1;                                                                                        \
+  GLfloat x[6],y[6];                                                                                             \
                                                                                                                  \
-  if (arrayninit) {                                                                                              \
-    for(Fi=0;Fi<6;Fi++) {                                                                                        \
-      x[Fi]=-cos( Fi*2*Pi/5 + Pi/10 )/(Divisions)*cossec36_2*(Edge);                                             \
-      y[Fi]=sin( Fi*2*Pi/5 + Pi/10 )/(Divisions)*cossec36_2*(Edge);                                              \
-    }                                                                                                            \
-    arrayninit=0;                                                                                                \
+  for(Fi=0;Fi<6;Fi++) {                                                                                          \
+    x[Fi]=-cos( Fi*2*Pi/5 + Pi/10 )/(Divisions)*cossec36_2*(Edge);                                               \
+    y[Fi]=sin( Fi*2*Pi/5 + Pi/10 )/(Divisions)*cossec36_2*(Edge);                                                \
   }                                                                                                              \
                                                                                                                  \
   for (Ri=1; Ri<=(Divisions); Ri++) {                                                                            \
@@ -282,25 +276,27 @@ static morph3dstruct *morph3d = NULL;
         Xf=(float)(Ri-Ti)*x[Fi] + (float)Ti*x[Fi+1];                                                             \
         Yf=(float)(Ri-Ti)*y[Fi] + (float)Ti*y[Fi+1];                                                             \
         Xa=Xf+0.001; Yb=Yf+0.001;                                                                                \
-       Factor=1-(((Xf2=sqr(Xf))+(Yf2=sqr(Yf)))*AmpVr2);                                                         \
-       Factor1=1-((sqr(Xa)+Yf2)*AmpVr2);                                                                        \
-       Factor2=1-((Xf2+sqr(Yb))*AmpVr2);                                                                        \
+       Factor=1-(((Xf2=sqr(Xf))+(Yf2=sqr(Yf)))*AmpVr2);                                                             \
+       Factor1=1-((sqr(Xa)+Yf2)*AmpVr2);                                                                            \
+       Factor2=1-((Xf2+sqr(Yb))*AmpVr2);                                                                            \
         VertX=Factor*Xf;        VertY=Factor*Yf;        VertZ=Factor*Zf;                                         \
         NeiAX=Factor1*Xa-VertX; NeiAY=Factor1*Yf-VertY; NeiAZ=Factor1*Zf-VertZ;                                  \
         NeiBX=Factor2*Xf-VertX; NeiBY=Factor2*Yb-VertY; NeiBZ=Factor2*Zf-VertZ;                                  \
         glNormal3f(VectMul(NeiAX, NeiAY, NeiAZ, NeiBX, NeiBY, NeiBZ));                                           \
-       glVertex3f(VertX, VertY, VertZ);                                                                         \
+               glVertex3f(VertX, VertY, VertZ);                                                                         \
+           mi->polygon_count++;                                                                                     \
                                                                                                                  \
         Xf-=x[Fi]; Yf-=y[Fi]; Xa-=x[Fi]; Yb-=y[Fi];                                                              \
                                                                                                                  \
-       Factor=1-(((Xf2=sqr(Xf))+(Yf2=sqr(Yf)))*AmpVr2);                                                         \
-       Factor1=1-((sqr(Xa)+Yf2)*AmpVr2);                                                                        \
-       Factor2=1-((Xf2+sqr(Yb))*AmpVr2);                                                                        \
+               Factor=1-(((Xf2=sqr(Xf))+(Yf2=sqr(Yf)))*AmpVr2);                                                         \
+               Factor1=1-((sqr(Xa)+Yf2)*AmpVr2);                                                                        \
+               Factor2=1-((Xf2+sqr(Yb))*AmpVr2);                                                                        \
         VertX=Factor*Xf;        VertY=Factor*Yf;        VertZ=Factor*Zf;                                         \
         NeiAX=Factor1*Xa-VertX; NeiAY=Factor1*Yf-VertY; NeiAZ=Factor1*Zf-VertZ;                                  \
         NeiBX=Factor2*Xf-VertX; NeiBY=Factor2*Yb-VertY; NeiBZ=Factor2*Zf-VertZ;                                  \
         glNormal3f(VectMul(NeiAX, NeiAY, NeiAZ, NeiBX, NeiBY, NeiBZ));                                           \
-       glVertex3f(VertX, VertY, VertZ);                                                                         \
+               glVertex3f(VertX, VertY, VertZ);                                                                         \
+           mi->polygon_count++;                                                                                     \
                                                                                                                  \
       }                                                                                                          \
       Xf=(float)Ri*x[Fi+1];                                                                                      \
@@ -317,218 +313,183 @@ static morph3dstruct *morph3d = NULL;
       glEnd();                                                                                                   \
     }                                                                                                            \
   }                                                                                                              \
-  VS=(Factor<0);                                                                                             \
+  VS=(Factor<0);                                                                                                    \
 }
 
 static void
 draw_tetra(ModeInfo * mi)
 {
-       GLuint      list;
-
        morph3dstruct *mp = &morph3d[MI_SCREEN(mi)];
 
        glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, mp->MaterialColor[0]);
 
-       list = glGenLists(1);
-       glNewList(list, GL_COMPILE_AND_EXECUTE);
        TRIANGLE(2, mp->seno, mp->edgedivisions, 0.5 / SQRT6, mp->VisibleSpikes);
-       glEndList();
 
        glPushMatrix();
        glRotatef(180, 0, 0, 1);
        glRotatef(-tetraangle, 1, 0, 0);
        glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, mp->MaterialColor[1]);
-       glCallList(list);
+       TRIANGLE(2, mp->seno, mp->edgedivisions, 0.5 / SQRT6, mp->VisibleSpikes);
        glPopMatrix();
        glPushMatrix();
        glRotatef(180, 0, 1, 0);
        glRotatef(-180 + tetraangle, 0.5, SQRT3 / 2, 0);
        glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, mp->MaterialColor[2]);
-       glCallList(list);
+       TRIANGLE(2, mp->seno, mp->edgedivisions, 0.5 / SQRT6, mp->VisibleSpikes);
        glPopMatrix();
        glRotatef(180, 0, 1, 0);
        glRotatef(-180 + tetraangle, 0.5, -SQRT3 / 2, 0);
        glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, mp->MaterialColor[3]);
-       glCallList(list);
-
-       glDeleteLists(list, 1);
+       TRIANGLE(2, mp->seno, mp->edgedivisions, 0.5 / SQRT6, mp->VisibleSpikes);
 }
 
 static void
 draw_cube(ModeInfo * mi)
 {
-       GLuint      list;
-
        morph3dstruct *mp = &morph3d[MI_SCREEN(mi)];
 
-
        glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, mp->MaterialColor[0]);
 
-       list = glGenLists(1);
-       glNewList(list, GL_COMPILE_AND_EXECUTE);
        SQUARE(2, mp->seno, mp->edgedivisions, 0.5, mp->VisibleSpikes)
-               glEndList();
 
        glRotatef(cubeangle, 1, 0, 0);
        glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, mp->MaterialColor[1]);
-       glCallList(list);
+       SQUARE(2, mp->seno, mp->edgedivisions, 0.5, mp->VisibleSpikes)
        glRotatef(cubeangle, 1, 0, 0);
        glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, mp->MaterialColor[2]);
-       glCallList(list);
+       SQUARE(2, mp->seno, mp->edgedivisions, 0.5, mp->VisibleSpikes)
        glRotatef(cubeangle, 1, 0, 0);
        glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, mp->MaterialColor[3]);
-       glCallList(list);
+       SQUARE(2, mp->seno, mp->edgedivisions, 0.5, mp->VisibleSpikes)
        glRotatef(cubeangle, 0, 1, 0);
        glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, mp->MaterialColor[4]);
-       glCallList(list);
+       SQUARE(2, mp->seno, mp->edgedivisions, 0.5, mp->VisibleSpikes)
        glRotatef(2 * cubeangle, 0, 1, 0);
        glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, mp->MaterialColor[5]);
-       glCallList(list);
-
-       glDeleteLists(list, 1);
+       SQUARE(2, mp->seno, mp->edgedivisions, 0.5, mp->VisibleSpikes)
 }
 
 static void
 draw_octa(ModeInfo * mi)
 {
-       GLuint      list;
-
        morph3dstruct *mp = &morph3d[MI_SCREEN(mi)];
 
        glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, mp->MaterialColor[0]);
-
-       list = glGenLists(1);
-       glNewList(list, GL_COMPILE_AND_EXECUTE);
        TRIANGLE(2, mp->seno, mp->edgedivisions, 1 / SQRT6, mp->VisibleSpikes);
-       glEndList();
 
        glPushMatrix();
        glRotatef(180, 0, 0, 1);
        glRotatef(-180 + octaangle, 1, 0, 0);
        glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, mp->MaterialColor[1]);
-       glCallList(list);
+       TRIANGLE(2, mp->seno, mp->edgedivisions, 1 / SQRT6, mp->VisibleSpikes);
        glPopMatrix();
        glPushMatrix();
        glRotatef(180, 0, 1, 0);
        glRotatef(-octaangle, 0.5, SQRT3 / 2, 0);
        glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, mp->MaterialColor[2]);
-       glCallList(list);
+       TRIANGLE(2, mp->seno, mp->edgedivisions, 1 / SQRT6, mp->VisibleSpikes);
        glPopMatrix();
        glPushMatrix();
        glRotatef(180, 0, 1, 0);
        glRotatef(-octaangle, 0.5, -SQRT3 / 2, 0);
        glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, mp->MaterialColor[3]);
-       glCallList(list);
+       TRIANGLE(2, mp->seno, mp->edgedivisions, 1 / SQRT6, mp->VisibleSpikes);
        glPopMatrix();
        glRotatef(180, 1, 0, 0);
        glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, mp->MaterialColor[4]);
-       glCallList(list);
+       TRIANGLE(2, mp->seno, mp->edgedivisions, 1 / SQRT6, mp->VisibleSpikes);
        glPushMatrix();
        glRotatef(180, 0, 0, 1);
        glRotatef(-180 + octaangle, 1, 0, 0);
        glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, mp->MaterialColor[5]);
-       glCallList(list);
+       TRIANGLE(2, mp->seno, mp->edgedivisions, 1 / SQRT6, mp->VisibleSpikes);
        glPopMatrix();
        glPushMatrix();
        glRotatef(180, 0, 1, 0);
        glRotatef(-octaangle, 0.5, SQRT3 / 2, 0);
        glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, mp->MaterialColor[6]);
-       glCallList(list);
+       TRIANGLE(2, mp->seno, mp->edgedivisions, 1 / SQRT6, mp->VisibleSpikes);
        glPopMatrix();
        glRotatef(180, 0, 1, 0);
        glRotatef(-octaangle, 0.5, -SQRT3 / 2, 0);
        glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, mp->MaterialColor[7]);
-       glCallList(list);
-
-       glDeleteLists(list, 1);
+       TRIANGLE(2, mp->seno, mp->edgedivisions, 1 / SQRT6, mp->VisibleSpikes);
 }
 
 static void
 draw_dodeca(ModeInfo * mi)
 {
-       GLuint      list;
-
        morph3dstruct *mp = &morph3d[MI_SCREEN(mi)];
 
 #define TAU ((SQRT5+1)/2)
 
        glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, mp->MaterialColor[0]);
 
-       list = glGenLists(1);
-       glNewList(list, GL_COMPILE_AND_EXECUTE);
        PENTAGON(1, mp->seno, mp->edgedivisions, sqr(TAU) * sqrt((TAU + 2) / 5) / 2, mp->VisibleSpikes);
-       glEndList();
 
        glPushMatrix();
        glRotatef(180, 0, 0, 1);
        glPushMatrix();
        glRotatef(-dodecaangle, 1, 0, 0);
        glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, mp->MaterialColor[1]);
-       glCallList(list);
+       PENTAGON(1, mp->seno, mp->edgedivisions, sqr(TAU) * sqrt((TAU + 2) / 5) / 2, mp->VisibleSpikes);
        glPopMatrix();
        glPushMatrix();
        glRotatef(-dodecaangle, cos72, sin72, 0);
        glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, mp->MaterialColor[2]);
-       glCallList(list);
+       PENTAGON(1, mp->seno, mp->edgedivisions, sqr(TAU) * sqrt((TAU + 2) / 5) / 2, mp->VisibleSpikes);
        glPopMatrix();
        glPushMatrix();
        glRotatef(-dodecaangle, cos72, -sin72, 0);
        glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, mp->MaterialColor[3]);
-       glCallList(list);
+       PENTAGON(1, mp->seno, mp->edgedivisions, sqr(TAU) * sqrt((TAU + 2) / 5) / 2, mp->VisibleSpikes);
        glPopMatrix();
        glPushMatrix();
        glRotatef(dodecaangle, cos36, -sin36, 0);
        glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, mp->MaterialColor[4]);
-       glCallList(list);
+       PENTAGON(1, mp->seno, mp->edgedivisions, sqr(TAU) * sqrt((TAU + 2) / 5) / 2, mp->VisibleSpikes);
        glPopMatrix();
        glRotatef(dodecaangle, cos36, sin36, 0);
        glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, mp->MaterialColor[5]);
-       glCallList(list);
+       PENTAGON(1, mp->seno, mp->edgedivisions, sqr(TAU) * sqrt((TAU + 2) / 5) / 2, mp->VisibleSpikes);
        glPopMatrix();
        glRotatef(180, 1, 0, 0);
        glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, mp->MaterialColor[6]);
-       glCallList(list);
+       PENTAGON(1, mp->seno, mp->edgedivisions, sqr(TAU) * sqrt((TAU + 2) / 5) / 2, mp->VisibleSpikes);
        glRotatef(180, 0, 0, 1);
        glPushMatrix();
        glRotatef(-dodecaangle, 1, 0, 0);
        glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, mp->MaterialColor[7]);
-       glCallList(list);
+       PENTAGON(1, mp->seno, mp->edgedivisions, sqr(TAU) * sqrt((TAU + 2) / 5) / 2, mp->VisibleSpikes);
        glPopMatrix();
        glPushMatrix();
        glRotatef(-dodecaangle, cos72, sin72, 0);
        glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, mp->MaterialColor[8]);
-       glCallList(list);
+       PENTAGON(1, mp->seno, mp->edgedivisions, sqr(TAU) * sqrt((TAU + 2) / 5) / 2, mp->VisibleSpikes);
        glPopMatrix();
        glPushMatrix();
        glRotatef(-dodecaangle, cos72, -sin72, 0);
        glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, mp->MaterialColor[9]);
-       glCallList(list);
+       PENTAGON(1, mp->seno, mp->edgedivisions, sqr(TAU) * sqrt((TAU + 2) / 5) / 2, mp->VisibleSpikes);
        glPopMatrix();
        glPushMatrix();
        glRotatef(dodecaangle, cos36, -sin36, 0);
        glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, mp->MaterialColor[10]);
-       glCallList(list);
+       PENTAGON(1, mp->seno, mp->edgedivisions, sqr(TAU) * sqrt((TAU + 2) / 5) / 2, mp->VisibleSpikes);
        glPopMatrix();
        glRotatef(dodecaangle, cos36, sin36, 0);
        glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, mp->MaterialColor[11]);
-       glCallList(list);
-
-       glDeleteLists(list, 1);
+       PENTAGON(1, mp->seno, mp->edgedivisions, sqr(TAU) * sqrt((TAU + 2) / 5) / 2, mp->VisibleSpikes);
 }
 
 static void
 draw_icosa(ModeInfo * mi)
 {
-       GLuint      list;
-
        morph3dstruct *mp = &morph3d[MI_SCREEN(mi)];
 
        glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, mp->MaterialColor[0]);
 
-       list = glGenLists(1);
-       glNewList(list, GL_COMPILE_AND_EXECUTE);
        TRIANGLE(1.5, mp->seno, mp->edgedivisions, (3 * SQRT3 + SQRT15) / 12, mp->VisibleSpikes);
-       glEndList();
 
        glPushMatrix();
 
@@ -536,163 +497,102 @@ draw_icosa(ModeInfo * mi)
        glRotatef(180, 0, 0, 1);
        glRotatef(-icoangle, 1, 0, 0);
        glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, mp->MaterialColor[1]);
-       glCallList(list);
+       TRIANGLE(1.5, mp->seno, mp->edgedivisions, (3 * SQRT3 + SQRT15) / 12, mp->VisibleSpikes);
        glPushMatrix();
        glRotatef(180, 0, 1, 0);
        glRotatef(-180 + icoangle, 0.5, SQRT3 / 2, 0);
        glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, mp->MaterialColor[2]);
-       glCallList(list);
+       TRIANGLE(1.5, mp->seno, mp->edgedivisions, (3 * SQRT3 + SQRT15) / 12, mp->VisibleSpikes);
        glPopMatrix();
        glRotatef(180, 0, 1, 0);
        glRotatef(-180 + icoangle, 0.5, -SQRT3 / 2, 0);
        glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, mp->MaterialColor[3]);
-       glCallList(list);
+       TRIANGLE(1.5, mp->seno, mp->edgedivisions, (3 * SQRT3 + SQRT15) / 12, mp->VisibleSpikes);
        glPopMatrix();
        glPushMatrix();
        glRotatef(180, 0, 1, 0);
        glRotatef(-180 + icoangle, 0.5, SQRT3 / 2, 0);
        glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, mp->MaterialColor[4]);
-       glCallList(list);
+       TRIANGLE(1.5, mp->seno, mp->edgedivisions, (3 * SQRT3 + SQRT15) / 12, mp->VisibleSpikes);
        glPushMatrix();
        glRotatef(180, 0, 1, 0);
        glRotatef(-180 + icoangle, 0.5, SQRT3 / 2, 0);
        glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, mp->MaterialColor[5]);
-       glCallList(list);
+       TRIANGLE(1.5, mp->seno, mp->edgedivisions, (3 * SQRT3 + SQRT15) / 12, mp->VisibleSpikes);
        glPopMatrix();
        glRotatef(180, 0, 0, 1);
        glRotatef(-icoangle, 1, 0, 0);
        glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, mp->MaterialColor[6]);
-       glCallList(list);
+       TRIANGLE(1.5, mp->seno, mp->edgedivisions, (3 * SQRT3 + SQRT15) / 12, mp->VisibleSpikes);
        glPopMatrix();
        glRotatef(180, 0, 1, 0);
        glRotatef(-180 + icoangle, 0.5, -SQRT3 / 2, 0);
        glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, mp->MaterialColor[7]);
-       glCallList(list);
+       TRIANGLE(1.5, mp->seno, mp->edgedivisions, (3 * SQRT3 + SQRT15) / 12, mp->VisibleSpikes);
        glPushMatrix();
        glRotatef(180, 0, 1, 0);
        glRotatef(-180 + icoangle, 0.5, -SQRT3 / 2, 0);
        glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, mp->MaterialColor[8]);
-       glCallList(list);
+       TRIANGLE(1.5, mp->seno, mp->edgedivisions, (3 * SQRT3 + SQRT15) / 12, mp->VisibleSpikes);
        glPopMatrix();
        glRotatef(180, 0, 0, 1);
        glRotatef(-icoangle, 1, 0, 0);
        glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, mp->MaterialColor[9]);
-       glCallList(list);
+       TRIANGLE(1.5, mp->seno, mp->edgedivisions, (3 * SQRT3 + SQRT15) / 12, mp->VisibleSpikes);
        glPopMatrix();
        glRotatef(180, 1, 0, 0);
        glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, mp->MaterialColor[10]);
-       glCallList(list);
+       TRIANGLE(1.5, mp->seno, mp->edgedivisions, (3 * SQRT3 + SQRT15) / 12, mp->VisibleSpikes);
        glPushMatrix();
        glRotatef(180, 0, 0, 1);
        glRotatef(-icoangle, 1, 0, 0);
        glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, mp->MaterialColor[11]);
-       glCallList(list);
+       TRIANGLE(1.5, mp->seno, mp->edgedivisions, (3 * SQRT3 + SQRT15) / 12, mp->VisibleSpikes);
        glPushMatrix();
        glRotatef(180, 0, 1, 0);
        glRotatef(-180 + icoangle, 0.5, SQRT3 / 2, 0);
        glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, mp->MaterialColor[12]);
-       glCallList(list);
+       TRIANGLE(1.5, mp->seno, mp->edgedivisions, (3 * SQRT3 + SQRT15) / 12, mp->VisibleSpikes);
        glPopMatrix();
        glRotatef(180, 0, 1, 0);
        glRotatef(-180 + icoangle, 0.5, -SQRT3 / 2, 0);
        glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, mp->MaterialColor[13]);
-       glCallList(list);
+       TRIANGLE(1.5, mp->seno, mp->edgedivisions, (3 * SQRT3 + SQRT15) / 12, mp->VisibleSpikes);
        glPopMatrix();
        glPushMatrix();
        glRotatef(180, 0, 1, 0);
        glRotatef(-180 + icoangle, 0.5, SQRT3 / 2, 0);
        glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, mp->MaterialColor[14]);
-       glCallList(list);
+       TRIANGLE(1.5, mp->seno, mp->edgedivisions, (3 * SQRT3 + SQRT15) / 12, mp->VisibleSpikes);
        glPushMatrix();
        glRotatef(180, 0, 1, 0);
        glRotatef(-180 + icoangle, 0.5, SQRT3 / 2, 0);
        glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, mp->MaterialColor[15]);
-       glCallList(list);
+       TRIANGLE(1.5, mp->seno, mp->edgedivisions, (3 * SQRT3 + SQRT15) / 12, mp->VisibleSpikes);
        glPopMatrix();
        glRotatef(180, 0, 0, 1);
        glRotatef(-icoangle, 1, 0, 0);
        glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, mp->MaterialColor[16]);
-       glCallList(list);
+       TRIANGLE(1.5, mp->seno, mp->edgedivisions, (3 * SQRT3 + SQRT15) / 12, mp->VisibleSpikes);
        glPopMatrix();
        glRotatef(180, 0, 1, 0);
        glRotatef(-180 + icoangle, 0.5, -SQRT3 / 2, 0);
        glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, mp->MaterialColor[17]);
-       glCallList(list);
+       TRIANGLE(1.5, mp->seno, mp->edgedivisions, (3 * SQRT3 + SQRT15) / 12, mp->VisibleSpikes);
        glPushMatrix();
        glRotatef(180, 0, 1, 0);
        glRotatef(-180 + icoangle, 0.5, -SQRT3 / 2, 0);
        glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, mp->MaterialColor[18]);
-       glCallList(list);
+       TRIANGLE(1.5, mp->seno, mp->edgedivisions, (3 * SQRT3 + SQRT15) / 12, mp->VisibleSpikes);
        glPopMatrix();
        glRotatef(180, 0, 0, 1);
        glRotatef(-icoangle, 1, 0, 0);
        glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, mp->MaterialColor[19]);
-       glCallList(list);
-
-       glDeleteLists(list, 1);
-}
-
-void
-draw_morph3d(ModeInfo * mi)
-{
-       morph3dstruct *mp = &morph3d[MI_SCREEN(mi)];
-
-       Display    *display = MI_DISPLAY(mi);
-       Window      window = MI_WINDOW(mi);
-
-       glDrawBuffer(GL_BACK);
-       glXMakeCurrent(display, window, mp->glx_context);
-
-       glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
-
-       glPushMatrix();
-
-       glTranslatef(0.0, 0.0, -10.0);
-
-       if (!MI_WIN_IS_ICONIC(mi)) {
-               glScalef(Scale4Window * mp->WindH / mp->WindW, Scale4Window, Scale4Window);
-               glTranslatef(2.5 * mp->WindW / mp->WindH * sin(mp->step * 1.11), 2.5 * cos(mp->step * 1.25 * 1.11), 0);
-       } else {
-               glScalef(Scale4Iconic * mp->WindH / mp->WindW, Scale4Iconic, Scale4Iconic);
-       }
-
-       glRotatef(mp->step * 100, 1, 0, 0);
-       glRotatef(mp->step * 95, 0, 1, 0);
-       glRotatef(mp->step * 90, 0, 0, 1);
-
-       mp->seno = (sin(mp->step) + 1.0 / 3.0) * (4.0 / 5.0) * mp->Magnitude;
-
-       if (mp->VisibleSpikes) {
-#ifdef DEBUG_CULL_FACE
-               int         loop;
-
-               for (loop = 0; loop < 20; loop++)
-                       mp->MaterialColor[loop] = MaterialGray;
-#endif
-               glDisable(GL_CULL_FACE);
-       } else {
-#ifdef DEBUG_CULL_FACE
-               int         loop;
-
-               for (loop = 0; loop < 20; loop++)
-                       mp->MaterialColor[loop] = MaterialWhite;
-#endif
-               glEnable(GL_CULL_FACE);
-       }
-
-       mp->draw_object(mi);
-
-       glPopMatrix();
-
-       glFlush();
-
-       glXSwapBuffers(display, window);
-
-       mp->step += 0.05;
+       TRIANGLE(1.5, mp->seno, mp->edgedivisions, (3 * SQRT3 + SQRT15) / 12, mp->VisibleSpikes);
 }
 
-static void
-reshape(ModeInfo * mi, int width, int height)
+ENTRYPOINT void
+reshape_morph3d(ModeInfo * mi, int width, int height)
 {
        morph3dstruct *mp = &morph3d[MI_SCREEN(mi)];
 
@@ -709,7 +609,6 @@ pinit(ModeInfo * mi)
        morph3dstruct *mp = &morph3d[MI_SCREEN(mi)];
 
        glClearDepth(1.0);
-       glClearColor(0.0, 0.0, 0.0, 1.0);
        glColor3f(1.0, 1.0, 1.0);
 
        glLightfv(GL_LIGHT0, GL_AMBIENT, ambient);
@@ -807,7 +706,7 @@ pinit(ModeInfo * mi)
                        mp->Magnitude = 2.5;
                        break;
        }
-       if (MI_WIN_IS_MONO(mi)) {
+       if (MI_IS_MONO(mi)) {
                int         loop;
 
                for (loop = 0; loop < 20; loop++)
@@ -815,46 +714,118 @@ pinit(ModeInfo * mi)
        }
 }
 
-void
+ENTRYPOINT void
 init_morph3d(ModeInfo * mi)
 {
-       int         screen = MI_SCREEN(mi);
        morph3dstruct *mp;
 
-       if (morph3d == NULL) {
-               if ((morph3d = (morph3dstruct *) calloc(MI_NUM_SCREENS(mi),
-                                           sizeof (morph3dstruct))) == NULL)
-                       return;
-       }
-       mp = &morph3d[screen];
+       MI_INIT (mi, morph3d, NULL);
+       mp = &morph3d[MI_SCREEN(mi)];
        mp->step = NRAND(90);
        mp->VisibleSpikes = 1;
 
-       mp->glx_context = init_GL(mi);
+       if ((mp->glx_context = init_GL(mi)) != NULL) {
 
-       reshape(mi, MI_WIN_WIDTH(mi), MI_WIN_HEIGHT(mi));
-       mp->object = MI_BATCHCOUNT(mi);
-       if (mp->object <= 0 || mp->object > 5)
-               mp->object = NRAND(5) + 1;
-       pinit(mi);
+               reshape_morph3d(mi, MI_WIDTH(mi), MI_HEIGHT(mi));
+               glDrawBuffer(GL_BACK);
+               mp->object = MI_COUNT(mi);
+               if (mp->object <= 0 || mp->object > 5)
+                       mp->object = NRAND(5) + 1;
+               pinit(mi);
+       } else {
+               MI_CLEARWINDOW(mi);
+       }
+}
+
+ENTRYPOINT void
+draw_morph3d(ModeInfo * mi)
+{
+       Display    *display = MI_DISPLAY(mi);
+       Window      window = MI_WINDOW(mi);
+       morph3dstruct *mp;
+
+       if (morph3d == NULL)
+               return;
+       mp = &morph3d[MI_SCREEN(mi)];
+
+       MI_IS_DRAWN(mi) = True;
+
+       if (!mp->glx_context)
+               return;
+
+    mi->polygon_count = 0;
+       glXMakeCurrent(display, window, *(mp->glx_context));
+
+       glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+
+       glPushMatrix();
+
+       glTranslatef(0.0, 0.0, -10.0);
+
+       if (!MI_IS_ICONIC(mi)) {
+               glScalef(Scale4Window * mp->WindH / mp->WindW, Scale4Window, Scale4Window);
+               glTranslatef(2.5 * mp->WindW / mp->WindH * sin(mp->step * 1.11), 2.5 * cos(mp->step * 1.25 * 1.11), 0);
+       } else {
+               glScalef(Scale4Iconic * mp->WindH / mp->WindW, Scale4Iconic, Scale4Iconic);
+       }
+
+# ifdef HAVE_MOBILE    /* Keep it the same relative size when rotated. */
+    {
+      GLfloat h = MI_HEIGHT(mi) / (GLfloat) MI_WIDTH(mi);
+      int o = (int) current_device_rotation();
+      if (o != 0 && o != 180 && o != -180)
+        glScalef (1/h, h, 1);
+    }
+# endif
+
+       glRotatef(mp->step * 100, 1, 0, 0);
+       glRotatef(mp->step * 95, 0, 1, 0);
+       glRotatef(mp->step * 90, 0, 0, 1);
+
+       mp->seno = (sin(mp->step) + 1.0 / 3.0) * (4.0 / 5.0) * mp->Magnitude;
+
+       if (mp->VisibleSpikes) {
+#ifdef DEBUG_CULL_FACE
+               int         loop;
+
+               for (loop = 0; loop < 20; loop++)
+                       mp->MaterialColor[loop] = MaterialGray;
+#endif
+               glDisable(GL_CULL_FACE);
+       } else {
+#ifdef DEBUG_CULL_FACE
+               int         loop;
+
+               for (loop = 0; loop < 20; loop++)
+                       mp->MaterialColor[loop] = MaterialWhite;
+#endif
+               glEnable(GL_CULL_FACE);
+       }
+
+       mp->draw_object(mi);
+
+       glPopMatrix();
+
+       if (MI_IS_FPS(mi)) do_fps (mi);
+       glXSwapBuffers(display, window);
+
+       mp->step += 0.05;
 }
 
-void
+#ifndef STANDALONE
+ENTRYPOINT void
 change_morph3d(ModeInfo * mi)
 {
        morph3dstruct *mp = &morph3d[MI_SCREEN(mi)];
 
+       if (!mp->glx_context)
+               return;
+
        mp->object = (mp->object) % 5 + 1;
        pinit(mi);
 }
-
-void
-release_morph3d(ModeInfo * mi)
-{
-       if (morph3d != NULL) {
-               (void) free((void *) morph3d);
-               morph3d = NULL;
-       }
-}
+#endif /* !STANDALONE */
 
 #endif
+
+XSCREENSAVER_MODULE ("Morph3D", morph3d)