Back to index

radiance  4R0+20100331
rglsurf.c
Go to the documentation of this file.
00001 #ifndef lint
00002 static const char RCSid[] = "$Id: rglsurf.c,v 3.12 2004/03/30 20:40:03 greg Exp $";
00003 #endif
00004 /*
00005  * Convert Radiance -> OpenGL surfaces.
00006  */
00007 
00008 #include "copyright.h"
00009 
00010 #include "radogl.h"
00011 
00012 #ifndef NSLICES
00013 #define NSLICES             18            /* number of quadric slices */
00014 #endif
00015 #ifndef NSTACKS
00016 #define NSTACKS             10            /* number of quadric stacks */
00017 #endif
00018 
00019 MATREC *curmat = NULL;                    /* current material */
00020 
00021 static int    curpolysize = 0;     /* outputting triangles/quads */
00022 
00023 static GLUquadricObj *gluqo;              /* shared quadric object */
00024 static GLUtesselator *gluto;              /* shared tessallation object */
00025 
00026 static char   *glu_rout = "unk";   /* active GLU routine */
00027 
00028 #define NOPOLY()     if (curpolysize) {glEnd(); curpolysize = 0;} else
00029 
00030 
00031 void
00032 setmaterial(mp, cent, ispoly)      /* prepare for new material */
00033 register MATREC      *mp;
00034 FVECT  cent;
00035 int    ispoly;
00036 {
00037        if (mp != curmat && domats) {
00038               NOPOLY();
00039               domatobj(curmat = mp, cent);
00040        } else if (!ispoly) {
00041               NOPOLY();
00042        }
00043 }
00044 
00045 
00046 double
00047 polyarea(cent, norm, n, v)  /* compute polygon area & normal */
00048 FVECT  cent, norm;   /* returned center and normal */
00049 int    n;            /* number of vertices */
00050 register FVECT       v[];   /* vertex list */
00051 {
00052        FVECT  v1, v2, v3;
00053        double d;
00054        register int  i;
00055 
00056        norm[0] = norm[1] = norm[2] = 0.;
00057        v1[0] = v[1][0] - v[0][0];
00058        v1[1] = v[1][1] - v[0][1];
00059        v1[2] = v[1][2] - v[0][2];
00060        for (i = 2; i < n; i++) {
00061               v2[0] = v[i][0] - v[0][0];
00062               v2[1] = v[i][1] - v[0][1];
00063               v2[2] = v[i][2] - v[0][2];
00064               fcross(v3, v1, v2);
00065               norm[0] += v3[0];
00066               norm[1] += v3[1];
00067               norm[2] += v3[2];
00068               VCOPY(v1, v2);
00069        }
00070        if (cent != NULL) {                /* compute center also */
00071               cent[0] = cent[1] = cent[2] = 0.;
00072               for (i = n; i--; ) {
00073                      cent[0] += v[i][0];
00074                      cent[1] += v[i][1];
00075                      cent[2] += v[i][2];
00076               }
00077               d = 1./n;
00078               cent[0] *= d; cent[1] *= d; cent[2] *= d;
00079        }
00080        return(normalize(norm)*.5);
00081 }
00082 
00083 
00084 static void
00085 glu_error(en)               /* report an error as a warning */
00086 GLenum en;
00087 {
00088        sprintf(errmsg, "GLU error %s: %s", glu_rout, gluErrorString(en));
00089        error(WARNING, errmsg);
00090 }
00091 
00092 
00093 static void
00094 myCombine(coords, vertex_data, weight, dataOut)
00095 register GLdouble    coords[3];
00096 GLdouble      *vertex_data[4];
00097 GLfloat       weight[4];
00098 GLdouble      **dataOut;
00099 {
00100        register GLdouble    *newvert;
00101 
00102        newvert = (GLdouble *)malloc(3*sizeof(GLdouble));
00103        if (newvert == NULL)
00104               error(SYSTEM, "out of memory in myCombine");
00105        VCOPY(newvert, coords);            /* no data, just coordinates */
00106        *dataOut = newvert;
00107 }
00108 
00109 
00110 static void
00111 newtess()                   /* allocate GLU tessellation object */
00112 {
00113        if ((gluto = gluNewTess()) == NULL)
00114               error(INTERNAL, "gluNewTess failed");
00115        gluTessCallback(gluto, GLU_TESS_BEGIN, glBegin);
00116        gluTessCallback(gluto, GLU_TESS_VERTEX, glVertex3dv);
00117        gluTessCallback(gluto, GLU_TESS_END, glEnd);
00118        gluTessCallback(gluto, GLU_TESS_COMBINE, myCombine);
00119        gluTessCallback(gluto, GLU_TESS_ERROR, glu_error);
00120        gluTessProperty(gluto, GLU_TESS_WINDING_RULE, GLU_TESS_WINDING_NONZERO);
00121 }
00122 
00123 
00124 static void
00125 newquadric()                /* allocate GLU quadric structure */
00126 {
00127        if ((gluqo = gluNewQuadric()) == NULL)
00128               error(INTERNAL, "gluNewQuadric failed");
00129        gluQuadricDrawStyle(gluqo, GLU_FILL);
00130        gluQuadricCallback(gluqo, GLU_ERROR, glu_error);
00131 }
00132 
00133 
00134 int
00135 o_face(o)                   /* convert a face */
00136 register OBJREC      *o;
00137 {
00138        double area;
00139        FVECT  norm, cent;
00140        register int  i;
00141 
00142        if ((o->oargs.nfargs < 9) | (o->oargs.nfargs % 3))
00143               objerror(o, USER, "bad # real arguments");
00144        area = polyarea(cent, norm, o->oargs.nfargs/3, (FVECT *)o->oargs.farg);
00145        if (area <= FTINY)
00146               return(0);
00147        if (dolights)                             /* check for source */
00148               doflatsrc((MATREC *)o->os, cent, norm, area);
00149        setmaterial((MATREC *)o->os, cent, 1);           /* set material */
00150        if (o->oargs.nfargs/3 != curpolysize) {
00151               if (curpolysize) glEnd();
00152               curpolysize = o->oargs.nfargs/3;
00153               if (curpolysize == 3)
00154                      glBegin(GL_TRIANGLES);
00155               else if (curpolysize == 4)
00156                      glBegin(GL_QUADS);
00157        }
00158        glNormal3d((GLdouble)norm[0], (GLdouble)norm[1], (GLdouble)norm[2]);
00159        if (curpolysize > 4) {
00160               if (gluto == NULL) newtess();
00161               glu_rout = "tessellating polygon";
00162               gluTessNormal(gluto, (GLdouble)norm[0],
00163                             (GLdouble)norm[1], (GLdouble)norm[2]);
00164               gluTessBeginPolygon(gluto, NULL);
00165               gluTessBeginContour(gluto);
00166 #ifdef SMLFLT
00167               error(INTERNAL, "bad code segment in o_face");
00168 #endif
00169               for (i = 0; i < curpolysize; i++)
00170                      gluTessVertex(gluto, (GLdouble *)(o->oargs.farg+3*i),
00171                                    (void *)(o->oargs.farg+3*i));
00172               gluTessEndContour(gluto);
00173               gluTessEndPolygon(gluto);
00174               curpolysize = 0;
00175        } else {
00176               for (i = 0; i < curpolysize; i++)
00177                      glVertex3d((GLdouble)o->oargs.farg[3*i],
00178                                    (GLdouble)o->oargs.farg[3*i+1],
00179                                    (GLdouble)o->oargs.farg[3*i+2]);
00180        }
00181        return(0);
00182 }
00183 
00184 
00185 void
00186 surfclean()                 /* clean up surface routines */
00187 {
00188        setmaterial(NULL, NULL, 0);
00189        if (gluqo != NULL) {
00190               gluDeleteQuadric(gluqo);
00191               gluqo = NULL;
00192        }
00193        if (gluto != NULL) {
00194               gluDeleteTess(gluto);
00195               gluto = NULL;
00196        }
00197        rgl_checkerr("in surfclean");
00198 }
00199 
00200 
00201 int
00202 o_sphere(o)                 /* convert a sphere */
00203 register OBJREC      *o;
00204 {
00205                                    /* check arguments */
00206        if (o->oargs.nfargs != 4)
00207               objerror(o, USER, "bad # real arguments");
00208        if (o->oargs.farg[3] < -FTINY) {
00209               o->otype = o->otype==OBJ_SPHERE ? OBJ_BUBBLE : OBJ_SPHERE;
00210               o->oargs.farg[3] = -o->oargs.farg[3];
00211        } else if (o->oargs.farg[3] <= FTINY)
00212               return(0);
00213        if (dolights)
00214               dosphsrc((MATREC *)o->os, o->oargs.farg,
00215                             PI*o->oargs.farg[3]*o->oargs.farg[3]);
00216        setmaterial((MATREC *)o->os, o->oargs.farg, 0);
00217        if (gluqo == NULL) newquadric();
00218        glu_rout = "making sphere";
00219        gluQuadricOrientation(gluqo,
00220                      o->otype==OBJ_BUBBLE ? GLU_INSIDE : GLU_OUTSIDE);
00221        gluQuadricNormals(gluqo, GLU_SMOOTH);
00222        glMatrixMode(GL_MODELVIEW);
00223        glPushMatrix();
00224        glTranslated((GLdouble)o->oargs.farg[0], (GLdouble)o->oargs.farg[1],
00225                      (GLdouble)o->oargs.farg[2]);
00226        gluSphere(gluqo, (GLdouble)o->oargs.farg[3], NSLICES, NSTACKS);
00227        glPopMatrix();
00228        return(0);
00229 }
00230 
00231 
00232 int
00233 o_cone(o)                   /* convert a cone or cylinder */
00234 register OBJREC *o;
00235 {
00236        double x1, y1, h, d;
00237        FVECT  cent;
00238        register int  iscyl;
00239 
00240        iscyl = (o->otype==OBJ_CYLINDER) | (o->otype==OBJ_TUBE);
00241        if (o->oargs.nfargs != (iscyl ? 7 : 8))
00242               objerror(o, USER, "bad # real arguments");
00243        if (o->oargs.farg[6] < -FTINY) {
00244               o->oargs.farg[6] = -o->oargs.farg[6];
00245               if (iscyl)
00246                      o->otype = o->otype==OBJ_CYLINDER ?
00247                                    OBJ_TUBE : OBJ_CYLINDER;
00248               else {
00249                      if ((o->oargs.farg[7] = -o->oargs.farg[7]) < -FTINY)
00250                             objerror(o, USER, "illegal radii");
00251                      o->otype = o->otype==OBJ_CONE ? OBJ_CUP : OBJ_CONE;
00252               }
00253        } else if (!iscyl && o->oargs.farg[7] < -FTINY)
00254               objerror(o, USER, "illegal radii");
00255        if (o->oargs.farg[6] <= FTINY && (iscyl || o->oargs.farg[7] <= FTINY))
00256               return(0);
00257        if (!iscyl) {
00258               if (o->oargs.farg[6] < 0.)  /* complains for tiny neg's */
00259                      o->oargs.farg[6] = 0.;
00260               if (o->oargs.farg[7] < 0.)
00261                      o->oargs.farg[7] = 0.;
00262        }
00263        h = sqrt(dist2(o->oargs.farg,o->oargs.farg+3));
00264        if (h <= FTINY)
00265               return(0);
00266        cent[0] = .5*(o->oargs.farg[0] + o->oargs.farg[3]);
00267        cent[1] = .5*(o->oargs.farg[1] + o->oargs.farg[4]);
00268        cent[2] = .5*(o->oargs.farg[2] + o->oargs.farg[5]);
00269        setmaterial((MATREC *)o->os, cent, 0);
00270        if (gluqo == NULL) newquadric();
00271        glu_rout = "making cylinder";
00272        gluQuadricOrientation(gluqo, (o->otype==OBJ_CUP) | (o->otype==OBJ_TUBE) ?
00273                      GLU_INSIDE : GLU_OUTSIDE);
00274        gluQuadricNormals(gluqo, GLU_SMOOTH);
00275        glMatrixMode(GL_MODELVIEW);
00276        glPushMatrix();
00277                                    /* do base translation */
00278        glTranslated((GLdouble)o->oargs.farg[0], (GLdouble)o->oargs.farg[1],
00279                      (GLdouble)o->oargs.farg[2]);
00280                                    /* compute height & rotation angle */
00281        x1 = o->oargs.farg[1] - o->oargs.farg[4];
00282        y1 = o->oargs.farg[3] - o->oargs.farg[0];
00283        /* z1 = 0; */
00284        d = x1*x1 + y1*y1;
00285        if (d <= FTINY*FTINY)
00286               x1 = 1.;
00287        else
00288               d = 180./PI * asin(sqrt(d) / h);
00289        if (o->oargs.farg[5] < o->oargs.farg[2])
00290               d = 180. - d;
00291        if (d > FTINY)
00292               glRotated(d, (GLdouble)x1, (GLdouble)y1, 0.);
00293        gluCylinder(gluqo, o->oargs.farg[6], o->oargs.farg[iscyl ? 6 : 7],
00294                      h, NSLICES, 1);
00295        glPopMatrix();
00296        return(0);
00297 }
00298 
00299 
00300 int
00301 o_ring(o)                   /* convert a ring */
00302 register OBJREC      *o;
00303 {
00304        double x1, y1, d, h;
00305 
00306        if (o->oargs.nfargs != 8)
00307               objerror(o, USER, "bad # real arguments");
00308        if (o->oargs.farg[7] < o->oargs.farg[6]) {
00309               register double      d = o->oargs.farg[7];
00310               o->oargs.farg[7] = o->oargs.farg[6];
00311               o->oargs.farg[6] = d;
00312        }
00313        if (o->oargs.farg[6] < -FTINY)
00314               objerror(o, USER, "negative radius");
00315        if (o->oargs.farg[6] < 0.)         /* complains for tiny neg's */
00316               o->oargs.farg[6] = 0.;
00317        if (o->oargs.farg[7] - o->oargs.farg[6] <= FTINY)
00318               return(0);
00319        h = VLEN(o->oargs.farg+3);
00320        if (h <= FTINY)
00321               return(0);
00322        if (dolights)
00323               doflatsrc((MATREC *)o->os, o->oargs.farg, o->oargs.farg+3, 
00324                             PI*(o->oargs.farg[7]*o->oargs.farg[7] -
00325                                    o->oargs.farg[6]*o->oargs.farg[6]));
00326        setmaterial((MATREC *)o->os, o->oargs.farg, 0);
00327        if (gluqo == NULL) newquadric();
00328        glu_rout = "making disk";
00329        gluQuadricOrientation(gluqo, GLU_OUTSIDE);
00330        gluQuadricNormals(gluqo, GLU_FLAT);
00331        glMatrixMode(GL_MODELVIEW);
00332        glPushMatrix();
00333        glTranslated((GLdouble)o->oargs.farg[0], (GLdouble)o->oargs.farg[1],
00334                      (GLdouble)o->oargs.farg[2]);
00335                                    /* compute rotation angle */
00336        x1 = -o->oargs.farg[4];
00337        y1 = o->oargs.farg[3];
00338        /* z1 = 0; */
00339        d = x1*x1 + y1*y1;
00340        if (d <= FTINY*FTINY)
00341               x1 = 1.;
00342        else
00343               d = 180./PI * asin(sqrt(d) / h);
00344        if (o->oargs.farg[5] < 0.)
00345               d = 180. - d;
00346        if (d > FTINY)
00347               glRotated(d, (GLdouble)x1, (GLdouble)y1, 0.);
00348        gluDisk(gluqo, o->oargs.farg[6], o->oargs.farg[7], NSLICES, 1);
00349        glPopMatrix();
00350        return(0);
00351 }