Main Page   Namespace List   Class Hierarchy   Alphabetical List   Compound List   File List   Namespace Members   Compound Members   File Members   Related Pages  

OpenGLRenderer.C

Go to the documentation of this file.
00001 /***************************************************************************
00002  *cr                                                                       
00003  *cr            (C) Copyright 1995-2016 The Board of Trustees of the           
00004  *cr                        University of Illinois                       
00005  *cr                         All Rights Reserved                        
00006  *cr                                                                   
00007  ***************************************************************************/
00008 
00009 /***************************************************************************
00010  * RCS INFORMATION:
00011  *
00012  *      $RCSfile: OpenGLRenderer.C,v $
00013  *      $Author: johns $        $Locker:  $             $State: Exp $
00014  *      $Revision: 1.466 $      $Date: 2018/11/05 04:39:34 $
00015  *
00016  ***************************************************************************
00017  * DESCRIPTION:
00018  *
00019  * Subclass of DisplayDevice, this object has routines used by all the
00020  * different display devices that use OpenGL for rendering.
00021  * Will render drawing commands into a window.
00022  * This is not the complete definition,
00023  * however, of a DisplayDevice; something must provide routines to open
00024  * windows, reshape, clear, set perspective, etc.  This object contains the
00025  * code to render a display command list.
00026  ***************************************************************************/
00027 
00028 #include "OpenGLRenderer.h"
00029 #include "DispCmds.h"
00030 #include "Inform.h"
00031 #include "utilities.h"
00032 #include "VMDDisplayList.h"
00033 #include "Hershey.h"
00034 
00035 #include <stdlib.h>
00036 #include <stdio.h>
00037 #include <math.h>
00038 #include "OpenGLStipples.h"
00039 
00040 // enable WireGL support
00041 #define VMDWIREGL 1
00042 
00043 // enable Intel SWR support
00044 #define VMDINTELSWR 1
00045 
00046 #if defined(VMDUSEOPENGLSHADER)
00047 #define VMDUSEGLSLSPHERES 1
00048 #if defined(GL_ARB_point_sprite)
00049 #define VMDUSEGLSLSPHERESPRITES 1
00050 #endif
00051 #endif
00052 
00053 #if 0
00054 #define OGLERR { GLenum err; if ((err = glGetError()) != GL_NO_ERROR) {  \
00055         msgErr << __FILE__ << " line " << __LINE__ << " " << \
00056         (const char *) gluErrorString(err) << sendmsg; }}
00057 #else 
00058 #define OGLERR
00059 #endif
00060 
00061 #define MIN_SPHERE_RES 4
00062 #define MAX_SPHERE_RES 30
00063 
00064 #if defined(VMDUSELIBGLU) 
00065 #define vmd_Project   gluProject
00066 #define vmd_UnProject gluUnProject
00067 #else
00068 //
00069 // VMD-internal replacements for GLU routines
00070 //
00071 static void vmd_matmult_4x4d(GLdouble *r, const GLdouble *m1, 
00072                              const GLdouble *m2) {
00073   r[ 0]=m1[0]*m2[ 0] + m1[4]*m2[ 1] + m1[ 8]*m2[ 2] + m1[12]*m2[ 3];
00074   r[ 4]=m1[0]*m2[ 4] + m1[4]*m2[ 5] + m1[ 8]*m2[ 6] + m1[12]*m2[ 7];
00075   r[ 8]=m1[0]*m2[ 8] + m1[4]*m2[ 9] + m1[ 8]*m2[10] + m1[12]*m2[11];
00076   r[12]=m1[0]*m2[12] + m1[4]*m2[13] + m1[ 8]*m2[14] + m1[12]*m2[15];
00077 
00078   r[ 1]=m1[1]*m2[ 0] + m1[5]*m2[ 1] + m1[ 9]*m2[ 2] + m1[13]*m2[ 3];
00079   r[ 5]=m1[1]*m2[ 4] + m1[5]*m2[ 5] + m1[ 9]*m2[ 6] + m1[13]*m2[ 7];
00080   r[ 9]=m1[1]*m2[ 8] + m1[5]*m2[ 9] + m1[ 9]*m2[10] + m1[13]*m2[11];
00081   r[13]=m1[1]*m2[12] + m1[5]*m2[13] + m1[ 9]*m2[14] + m1[13]*m2[15];
00082 
00083   r[ 2]=m1[2]*m2[ 0] + m1[6]*m2[ 1] + m1[10]*m2[ 2] + m1[14]*m2[ 3];
00084   r[ 6]=m1[2]*m2[ 4] + m1[6]*m2[ 5] + m1[10]*m2[ 6] + m1[14]*m2[ 7];
00085   r[10]=m1[2]*m2[ 8] + m1[6]*m2[ 9] + m1[10]*m2[10] + m1[14]*m2[11];
00086   r[14]=m1[2]*m2[12] + m1[6]*m2[13] + m1[10]*m2[14] + m1[14]*m2[15];
00087 
00088   r[ 3]=m1[3]*m2[ 0] + m1[7]*m2[ 1] + m1[11]*m2[ 2] + m1[15]*m2[ 3];
00089   r[ 7]=m1[3]*m2[ 4] + m1[7]*m2[ 5] + m1[11]*m2[ 6] + m1[15]*m2[ 7];
00090   r[11]=m1[3]*m2[ 8] + m1[7]*m2[ 9] + m1[11]*m2[10] + m1[15]*m2[11];
00091   r[15]=m1[3]*m2[12] + m1[7]*m2[13] + m1[11]*m2[14] + m1[15]*m2[15];
00092 }
00093 
00094 
00095 static void vmd_matmultvec_4x4d(GLdouble *npoint, const GLdouble *opoint, 
00096                                const GLdouble *mat) {
00097   npoint[0]=opoint[0]*mat[0]+opoint[1]*mat[4]+opoint[2]*mat[8]+opoint[3]*mat[12];
00098   npoint[1]=opoint[0]*mat[1]+opoint[1]*mat[5]+opoint[2]*mat[9]+opoint[3]*mat[13];
00099   npoint[2]=opoint[0]*mat[2]+opoint[1]*mat[6]+opoint[2]*mat[10]+opoint[3]*mat[14];
00100   npoint[3]=opoint[0]*mat[3]+opoint[1]*mat[7]+opoint[2]*mat[11]+opoint[3]*mat[15];
00101 }
00102 
00103 #define SWAP_ROWS_DOUBLE(a, b) { double *_tmp = a; (a)=(b); (b)=_tmp; }
00104 #define SWAP_ROWS_FLOAT(a, b)  { float *_tmp = a; (a)=(b); (b)=_tmp; }
00105 #define SWAP_ROWS SWAP_ROWS_DOUBLE
00106 #define MAT(m,r,c) (m)[(c)*4+(r)]
00107 
00108  
00109 static int vmd_invert_mat_4x4d(const GLdouble *m, GLdouble *out) {
00110   double wtmp[4][8];
00111   double m0, m1, m2, m3, s;
00112   double *r0, *r1, *r2, *r3;
00113 
00114   r0 = wtmp[0], r1 = wtmp[1], r2 = wtmp[2], r3 = wtmp[3];
00115 
00116   r0[0] = MAT(m, 0, 0), r0[1] = MAT(m, 0, 1),
00117   r0[2] = MAT(m, 0, 2), r0[3] = MAT(m, 0, 3),
00118   r0[4] = 1.0, r0[5] = r0[6] = r0[7] = 0.0,
00119   r1[0] = MAT(m, 1, 0), r1[1] = MAT(m, 1, 1),
00120   r1[2] = MAT(m, 1, 2), r1[3] = MAT(m, 1, 3),
00121   r1[5] = 1.0, r1[4] = r1[6] = r1[7] = 0.0,
00122   r2[0] = MAT(m, 2, 0), r2[1] = MAT(m, 2, 1),
00123   r2[2] = MAT(m, 2, 2), r2[3] = MAT(m, 2, 3),
00124   r2[6] = 1.0, r2[4] = r2[5] = r2[7] = 0.0,
00125   r3[0] = MAT(m, 3, 0), r3[1] = MAT(m, 3, 1),
00126   r3[2] = MAT(m, 3, 2), r3[3] = MAT(m, 3, 3),
00127   r3[7] = 1.0, r3[4] = r3[5] = r3[6] = 0.0;
00128 
00129   /* choose pivot - or die */
00130   if (fabs(r3[0]) > fabs(r2[0]))
00131     SWAP_ROWS(r3, r2);
00132   if (fabs(r2[0]) > fabs(r1[0]))
00133     SWAP_ROWS(r2, r1);
00134   if (fabs(r1[0]) > fabs(r0[0]))
00135     SWAP_ROWS(r1, r0);
00136   if (0.0 == r0[0])
00137     return 0;
00138 
00139   /* eliminate first variable     */
00140   m1 = r1[0] / r0[0];
00141   m2 = r2[0] / r0[0];
00142   m3 = r3[0] / r0[0];
00143   s = r0[1];
00144   r1[1] -= m1 * s;
00145   r2[1] -= m2 * s;
00146   r3[1] -= m3 * s;
00147   s = r0[2];
00148   r1[2] -= m1 * s;
00149   r2[2] -= m2 * s;
00150   r3[2] -= m3 * s;
00151   s = r0[3];
00152   r1[3] -= m1 * s;
00153   r2[3] -= m2 * s;
00154   r3[3] -= m3 * s;
00155   s = r0[4];
00156   if (s != 0.0) {
00157     r1[4] -= m1 * s;
00158     r2[4] -= m2 * s;
00159     r3[4] -= m3 * s;
00160   }
00161   s = r0[5];
00162   if (s != 0.0) {
00163     r1[5] -= m1 * s;
00164     r2[5] -= m2 * s;
00165     r3[5] -= m3 * s;
00166   }
00167   s = r0[6];
00168   if (s != 0.0) {
00169     r1[6] -= m1 * s;
00170     r2[6] -= m2 * s;
00171     r3[6] -= m3 * s;
00172   }
00173   s = r0[7];
00174   if (s != 0.0) {
00175     r1[7] -= m1 * s;
00176     r2[7] -= m2 * s;
00177     r3[7] -= m3 * s;
00178   }
00179 
00180   /* choose pivot - or die */
00181   if (fabs(r3[1]) > fabs(r2[1]))
00182     SWAP_ROWS(r3, r2);
00183   if (fabs(r2[1]) > fabs(r1[1]))
00184     SWAP_ROWS(r2, r1);
00185   if (0.0 == r1[1])
00186     return 0;
00187 
00188   /* eliminate second variable */
00189   m2 = r2[1] / r1[1];
00190   m3 = r3[1] / r1[1];
00191   r2[2] -= m2 * r1[2];
00192   r3[2] -= m3 * r1[2];
00193   r2[3] -= m2 * r1[3];
00194   r3[3] -= m3 * r1[3];
00195   s = r1[4];
00196   if (0.0 != s) {
00197     r2[4] -= m2 * s;
00198     r3[4] -= m3 * s;
00199   }
00200   s = r1[5];
00201   if (0.0 != s) {
00202     r2[5] -= m2 * s;
00203     r3[5] -= m3 * s;
00204   }
00205   s = r1[6];
00206   if (0.0 != s) {
00207     r2[6] -= m2 * s;
00208     r3[6] -= m3 * s;
00209   }
00210   s = r1[7];
00211   if (0.0 != s) {
00212     r2[7] -= m2 * s;
00213     r3[7] -= m3 * s;
00214   }
00215 
00216   /* choose pivot - or die */
00217   if (fabs(r3[2]) > fabs(r2[2]))
00218     SWAP_ROWS(r3, r2);
00219   if (0.0 == r2[2])
00220     return 0;
00221 
00222   /* eliminate third variable */
00223   m3 = r3[2] / r2[2];
00224   r3[3] -= m3 * r2[3], r3[4] -= m3 * r2[4],
00225   r3[5] -= m3 * r2[5], r3[6] -= m3 * r2[6], r3[7] -= m3 * r2[7];
00226 
00227   /* last check */
00228   if (0.0 == r3[3])
00229     return 0;
00230 
00231   s = 1.0 / r3[3];              /* now back substitute row 3 */
00232   r3[4] *= s;
00233   r3[5] *= s;
00234   r3[6] *= s;
00235   r3[7] *= s;
00236 
00237   m2 = r2[3];                   /* now back substitute row 2 */
00238   s = 1.0 / r2[2];
00239   r2[4] = s * (r2[4] - r3[4] * m2), r2[5] = s * (r2[5] - r3[5] * m2),
00240   r2[6] = s * (r2[6] - r3[6] * m2), r2[7] = s * (r2[7] - r3[7] * m2);
00241 
00242   m1 = r1[3];
00243   r1[4] -= r3[4] * m1, r1[5] -= r3[5] * m1,
00244   r1[6] -= r3[6] * m1, r1[7] -= r3[7] * m1;
00245 
00246   m0 = r0[3];
00247   r0[4] -= r3[4] * m0, r0[5] -= r3[5] * m0,
00248   r0[6] -= r3[6] * m0, r0[7] -= r3[7] * m0;
00249 
00250   m1 = r1[2];                   /* now back substitute row 1 */
00251   s = 1.0 / r1[1];
00252   r1[4] = s * (r1[4] - r2[4] * m1), r1[5] = s * (r1[5] - r2[5] * m1),
00253   r1[6] = s * (r1[6] - r2[6] * m1), r1[7] = s * (r1[7] - r2[7] * m1);
00254   m0 = r0[2];
00255   r0[4] -= r2[4] * m0, r0[5] -= r2[5] * m0,
00256   r0[6] -= r2[6] * m0, r0[7] -= r2[7] * m0;
00257 
00258   m0 = r0[1];                   /* now back substitute row 0 */
00259   s = 1.0 / r0[0];
00260   r0[4] = s * (r0[4] - r1[4] * m0), r0[5] = s * (r0[5] - r1[5] * m0),
00261   r0[6] = s * (r0[6] - r1[6] * m0), r0[7] = s * (r0[7] - r1[7] * m0);
00262 
00263   MAT(out, 0, 0) = r0[4];
00264   MAT(out, 0, 1) = r0[5], MAT(out, 0, 2) = r0[6];
00265   MAT(out, 0, 3) = r0[7], MAT(out, 1, 0) = r1[4];
00266   MAT(out, 1, 1) = r1[5], MAT(out, 1, 2) = r1[6];
00267   MAT(out, 1, 3) = r1[7], MAT(out, 2, 0) = r2[4];
00268   MAT(out, 2, 1) = r2[5], MAT(out, 2, 2) = r2[6];
00269   MAT(out, 2, 3) = r2[7], MAT(out, 3, 0) = r3[4];
00270   MAT(out, 3, 1) = r3[5], MAT(out, 3, 2) = r3[6];
00271   MAT(out, 3, 3) = r3[7];
00272 
00273   return 1;
00274 }
00275 
00276 
00277 static GLdouble * vmd_vec_normalize_3d(GLdouble *vect) {
00278   GLdouble len2 = vect[0]*vect[0] + vect[1]*vect[1] + vect[2]*vect[2];
00279 
00280   // prevent division by zero
00281   if (len2 > 0) {
00282     GLdouble rescale = 1.0 / sqrt(len2);
00283     vect[0] *= rescale;
00284     vect[1] *= rescale;
00285     vect[2] *= rescale;
00286   }
00287 
00288   return vect;
00289 }
00290 
00291 
00292 static GLdouble * vmd_cross_3d(GLdouble *x1, const GLdouble *x2, 
00293                                const GLdouble *x3) {
00294   x1[0] =  x2[1]*x3[2] - x3[1]*x2[2];
00295   x1[1] = -x2[0]*x3[2] + x3[0]*x2[2];
00296   x1[2] =  x2[0]*x3[1] - x3[0]*x2[1];
00297 
00298   return x1;
00299 }
00300 
00301 
00302 static void vmd_mattrans_d(GLdouble *m, GLdouble x, GLdouble y, GLdouble z) {
00303   m[12] = m[0]*x + m[4]*y + m[ 8]*z + m[12];
00304   m[13] = m[1]*x + m[5]*y + m[ 9]*z + m[13];
00305   m[14] = m[2]*x + m[6]*y + m[10]*z + m[14];
00306   m[15] = m[3]*x + m[7]*y + m[11]*z + m[15];
00307 }
00308 
00309 
00310 static void vmd_mat_identity_4x4d(GLdouble *m) {
00311   memset((void *)m, 0, 16*sizeof(GLdouble));
00312   m[0]=1.0;
00313   m[5]=1.0;
00314   m[10]=1.0;
00315   m[15]=1.0;
00316 }
00317 
00318 
00319 #define SPHEREMAXRES 30
00320 static void vmd_DrawSphere(float rad, int res, int solid) {
00321   int i, j;
00322   float zLo, zHi, radLo, radHi, stn, ctn;
00323 
00324   float sinLong[SPHEREMAXRES];
00325   float cosLong[SPHEREMAXRES];
00326   float sinLatVert[SPHEREMAXRES];
00327   float cosLatVert[SPHEREMAXRES];
00328   float sinLatNorm[SPHEREMAXRES];
00329   float cosLatNorm[SPHEREMAXRES];
00330 
00331   if (res < 2)
00332     res = 2;
00333 
00334   if (res >= SPHEREMAXRES)
00335     res = SPHEREMAXRES-1;
00336 
00337   // longitudinal "slices"
00338   float ang_twopi_res = VMD_TWOPI / res;
00339   for (i=0; i<res; i++) {
00340     float angle = i * ang_twopi_res;
00341     sinLong[i] = sinf(angle);
00342     cosLong[i] = cosf(angle);
00343   }
00344   // ensure that longitude end point exactly matches start
00345   sinLong[res] = 0.0f; // sinLong[0]
00346   cosLong[res] = 1.0f; // cosLong[0]
00347 
00348   // latitude "stacks"
00349   float ang_pi_res = VMD_PI / res;
00350   for (i=0; i<=res; i++) {
00351     float angle = i * ang_pi_res;
00352     sinLatNorm[i] = sinf(angle);
00353     cosLatNorm[i] = cosf(angle);
00354     sinLatVert[i] = rad * sinLatNorm[i];
00355     cosLatVert[i] = rad * cosLatNorm[i];
00356   }
00357   // ensure top and bottom poles come to points
00358   sinLatVert[0] = 0;
00359   sinLatVert[res] = 0;
00360 
00361   // draw sphere caps as triangle fans, lower cap, j==0
00362   if (solid) {
00363     radLo = sinLatVert[1];
00364     zLo   = cosLatVert[1];
00365     stn   = sinLatNorm[1];
00366     ctn   = cosLatNorm[1];
00367 
00368     glNormal3f(sinLong[0] * sinLatNorm[0], 
00369                cosLong[0] * sinLatNorm[0], 
00370                cosLatNorm[0]);
00371 
00372     glBegin(GL_TRIANGLE_FAN);
00373     glVertex3f(0.0, 0.0, rad);
00374     for (i=res; i>=0; i--) {
00375       glNormal3f(sinLong[i] * stn, cosLong[i] * stn, ctn);
00376       glVertex3f(radLo * sinLong[i], radLo * cosLong[i], zLo);
00377     }
00378     glEnd();
00379   }
00380 
00381   // draw sphere caps as triangle fans, high cap, j==(res-1)
00382   radHi = sinLatVert[res-1];
00383   zHi   = cosLatVert[res-1];
00384   stn   = sinLatNorm[res-1];
00385   ctn   = cosLatNorm[res-1];
00386 
00387   if (solid) {
00388     glNormal3f(sinLong[res] * sinLatNorm[res], 
00389                cosLong[res] * sinLatNorm[res], 
00390                cosLatNorm[res]);
00391 
00392     glBegin(GL_TRIANGLE_FAN);
00393     glVertex3f(0.0, 0.0, -rad);
00394     for (i=0; i<=res; i++) {
00395       glNormal3f(sinLong[i] * stn, cosLong[i] * stn, ctn);
00396       glVertex3f(radHi * sinLong[i], radHi * cosLong[i], zHi);
00397     }
00398     glEnd();
00399   } else {
00400     glBegin(GL_POINTS);
00401     glVertex3f(0.0, 0.0,  rad); // draw both apex and base points at once
00402     glVertex3f(0.0, 0.0, -rad);
00403     for (i=0; i<=res; i++)
00404       glVertex3f(radHi * sinLong[i], radHi * cosLong[i], zHi);
00405     glEnd();
00406   }
00407   for (j=1; j<res-1; j++) {
00408     zLo = cosLatVert[j];
00409     zHi = cosLatVert[j+1];
00410 
00411     float stv1 = sinLatVert[j];
00412     float stv2 = sinLatVert[j+1];
00413 
00414     float stn1 = sinLatNorm[j];
00415     float ctn1 = cosLatNorm[j];
00416     float stn2 = sinLatNorm[j+1];
00417     float ctn2 = cosLatNorm[j+1];
00418 
00419     if (solid) {
00420       glBegin(GL_QUAD_STRIP);
00421       for (i=0; i<=res; i++) {
00422         glNormal3f(sinLong[i] * stn2, cosLong[i] * stn2, ctn2);
00423         glVertex3f(stv2 * sinLong[i], stv2 * cosLong[i], zHi);
00424         glNormal3f(sinLong[i] * stn1, cosLong[i] * stn1, ctn1);
00425         glVertex3f(stv1 * sinLong[i], stv1 * cosLong[i], zLo);
00426       }
00427       glEnd();
00428     } else {
00429       glBegin(GL_POINTS);
00430       for (i=0; i<=res; i++)
00431         glVertex3f(stv1 * sinLong[i], stv1 * cosLong[i], zLo);
00432       glEnd();
00433     }
00434   }
00435 }
00436 
00437 
00438 // Routine to draw a truncated cone with caps, adapted from the fallback
00439 // triangulated code path in FileRenderer::cone_trunc()
00440 static void vmd_DrawConic(float *base, float *apex, float radius, float radius2, int numsides) {
00441   int h;
00442   float theta, incTheta, cosTheta, sinTheta;
00443   float axis[3], temp[3], perp[3], perp2[3];
00444   float vert0[3], vert1[3], vert2[3], edge0[3], edge1[3], face0[3], face1[3], norm0[3], norm1[3];
00445 
00446   axis[0] = base[0] - apex[0];
00447   axis[1] = base[1] - apex[1];
00448   axis[2] = base[2] - apex[2];
00449   vec_normalize(axis);
00450 
00451   // Find an arbitrary vector that is not the axis and has non-zero length
00452   temp[0] = axis[0] - 1.0f;
00453   temp[1] = 1.0f;
00454   temp[2] = 1.0f;
00455 
00456   // use the cross product to find orthogonal vectors
00457   cross_prod(perp, axis, temp);
00458   vec_normalize(perp);
00459   cross_prod(perp2, axis, perp); // shouldn't need normalization
00460 
00461   // Draw the triangles
00462   incTheta = (float) VMD_TWOPI / numsides;
00463   theta = 0.0;
00464 
00465   // if radius2 is larger than zero, we will draw quadrilateral
00466   // panels rather than triangular panels
00467   if (radius2 > 0) {
00468     float negaxis[3], offsetL[3], offsetT[3], vert3[3];
00469     int filled=1;
00470     vec_negate(negaxis, axis);
00471     memset(vert0, 0, sizeof(vert0));
00472     memset(vert1, 0, sizeof(vert1));
00473     memset(norm0, 0, sizeof(norm0));
00474 
00475     glBegin(GL_TRIANGLES);
00476     for (h=0; h <= numsides+3; h++) {
00477       // project 2-D unit circles onto perp/perp2 3-D basis vectors
00478       // and scale to desired radii
00479       cosTheta = (float) cosf(theta);
00480       sinTheta = (float) sinf(theta);
00481       offsetL[0] = radius2 * (cosTheta*perp[0] + sinTheta*perp2[0]);
00482       offsetL[1] = radius2 * (cosTheta*perp[1] + sinTheta*perp2[1]);
00483       offsetL[2] = radius2 * (cosTheta*perp[2] + sinTheta*perp2[2]);
00484       offsetT[0] = radius  * (cosTheta*perp[0] + sinTheta*perp2[0]);
00485       offsetT[1] = radius  * (cosTheta*perp[1] + sinTheta*perp2[1]);
00486       offsetT[2] = radius  * (cosTheta*perp[2] + sinTheta*perp2[2]);
00487 
00488       // copy old vertices
00489       vec_copy(vert2, vert0);
00490       vec_copy(vert3, vert1);
00491       vec_copy(norm1, norm0);
00492 
00493       // calculate new vertices
00494       vec_add(vert0, base, offsetT);
00495       vec_add(vert1, apex, offsetL);
00496 
00497       // Use the new vertex to find new edges
00498       edge0[0] = vert0[0] - vert1[0];
00499       edge0[1] = vert0[1] - vert1[1];
00500       edge0[2] = vert0[2] - vert1[2];
00501       edge1[0] = vert0[0] - vert2[0];
00502       edge1[1] = vert0[1] - vert2[1];
00503       edge1[2] = vert0[2] - vert2[2];
00504 
00505       // Use the new edge to find a new facet normal
00506       cross_prod(norm0, edge1, edge0);
00507       vec_normalize(norm0);
00508 
00509       if (h > 2) {
00510         // Use the new normal to draw the previous side
00511         glNormal3fv(norm0);
00512         glVertex3fv(vert0);
00513         glNormal3fv(norm1);
00514         glVertex3fv(vert3);
00515         glNormal3fv(norm0);
00516         glVertex3fv(vert1);
00517 
00518         glNormal3fv(norm1);
00519         glVertex3fv(vert3);
00520         glNormal3fv(norm0);
00521         glVertex3fv(vert0);
00522         glNormal3fv(norm1);
00523         glVertex3fv(vert2);
00524 
00525         // Draw cylinder caps
00526         if (filled & CYLINDER_LEADINGCAP) {
00527           glNormal3fv(axis);
00528           glVertex3fv(vert1);
00529           glNormal3fv(axis);
00530           glVertex3fv(vert3);
00531           glNormal3fv(axis);
00532           glVertex3fv(apex);
00533         }
00534         if (filled & CYLINDER_TRAILINGCAP) {
00535           glNormal3fv(negaxis);
00536           glVertex3fv(vert0);
00537           glNormal3fv(negaxis);
00538           glVertex3fv(vert2);
00539           glNormal3fv(negaxis);
00540           glVertex3fv(base);
00541         }
00542       }
00543 
00544       theta += incTheta;
00545     }
00546     glEnd();
00547   } else {
00548     // radius2 is zero, so we draw triangular panels joined at the apex
00549     glBegin(GL_TRIANGLES);
00550     for (h=0; h < numsides+3; h++) {
00551       // project 2-D unit circle onto perp/perp2 3-D basis vectors
00552       // and scale to desired radius
00553       cosTheta = (float) cosf(theta);
00554       sinTheta = (float) sinf(theta);
00555       vert0[0] = base[0] + radius * (cosTheta*perp[0] + sinTheta*perp2[0]);
00556       vert0[1] = base[1] + radius * (cosTheta*perp[1] + sinTheta*perp2[1]);
00557       vert0[2] = base[2] + radius * (cosTheta*perp[2] + sinTheta*perp2[2]);
00558 
00559       // Use the new vertex to find a new edge
00560       edge0[0] = vert0[0] - apex[0];
00561       edge0[1] = vert0[1] - apex[1];
00562       edge0[2] = vert0[2] - apex[2];
00563 
00564       if (h > 0) {
00565         // Use the new edge to find a new face
00566         cross_prod(face0, edge0, edge1);
00567         vec_normalize(face0);
00568 
00569         if (h > 1) {
00570           // Use the new face to find the normal of the previous triangle
00571           norm0[0] = (face1[0] + face0[0]) * 0.5f;
00572           norm0[1] = (face1[1] + face0[1]) * 0.5f;
00573           norm0[2] = (face1[2] + face0[2]) * 0.5f;
00574           vec_normalize(norm0);
00575 
00576           if (h > 2) {
00577             // Use the new normal to draw the previous side and base of the cone
00578             glNormal3fv(norm0);
00579             glVertex3fv(vert1);
00580             glNormal3fv(norm1);
00581             glVertex3fv(vert2);
00582             glNormal3fv(face1);
00583             glVertex3fv(apex);
00584 
00585             glNormal3fv(axis);
00586             glVertex3fv(vert2);
00587             glNormal3fv(axis);
00588             glVertex3fv(vert1);
00589             glNormal3fv(axis);
00590             glVertex3fv(base);
00591           }
00592         }
00593 
00594         // Copy the old values
00595         memcpy(norm1, norm0, 3*sizeof(float));
00596         memcpy(vert2, vert1, 3*sizeof(float));
00597         memcpy(face1, face0, 3*sizeof(float));
00598       }
00599       memcpy(vert1, vert0, 3*sizeof(float));
00600       memcpy(edge1, edge0, 3*sizeof(float));
00601 
00602       theta += incTheta;
00603     }
00604     glEnd();
00605   }
00606 }
00607 
00608 
00609 static GLint vmd_Project(GLdouble objX,
00610                          GLdouble objY,
00611                          GLdouble objZ,
00612                          const GLdouble *model,
00613                          const GLdouble *proj,
00614                          const GLint *view,
00615                          GLdouble *winX,
00616                          GLdouble *winY,
00617                          GLdouble *winZ) {
00618 #if !defined(VMDUSELIBGLU) 
00619   // replaced previous implementation with one that also works correctly
00620   // for orthographic projections
00621   double in[4], tmp[4], out[4];
00622 
00623   in[0]=objX;
00624   in[1]=objY;
00625   in[2]=objZ;
00626   in[3]=1.0;
00627 
00628   vmd_matmultvec_4x4d(tmp,  in, model);
00629   vmd_matmultvec_4x4d(out, tmp, proj);
00630 
00631   if (out[3] == 0.0) 
00632     return 0;
00633 
00634   // efficiently map coordinates to range 0-1, and then to the viewport
00635   double tinv = 0.5 / out[3];
00636   *winX = (out[0] * tinv + 0.5) * view[2] + view[0];
00637   *winY = (out[1] * tinv + 0.5) * view[3] + view[1]; 
00638   *winZ = out[2] * tinv + 0.5;
00639 
00640   return 1;
00641 #else
00642   return gluProject(objX, objY, objZ, model, proj, view, winX, winY, winZ);
00643 #endif
00644 }
00645 
00646 
00647 static GLint vmd_UnProject(GLdouble winX,
00648                            GLdouble winY,
00649                            GLdouble winZ,
00650                            const GLdouble *model,
00651                            const GLdouble *proj,
00652                            const GLint *view,
00653                            GLdouble *objX,
00654                            GLdouble *objY,
00655                            GLdouble *objZ) {
00656 #if !defined(VMDUSELIBGLU) 
00657   // based on opengl.org wiki sample
00658   GLdouble m[16], A[16], in[4], out[4];
00659   memset(m, 0, sizeof(m));
00660 
00661   // invert matrix, compute projection * modelview, store in A
00662   vmd_matmult_4x4d(A, proj, model);
00663   if (vmd_invert_mat_4x4d(A, m) == 0)
00664     return 0;
00665 
00666   in[0]=((winX-(double)view[0])/(double)view[2])*2.0 - 1.0;
00667   in[1]=((winY-(double)view[1])/(double)view[3])*2.0 - 1.0;
00668   in[2]=winZ*2.0 - 1.0;
00669   in[3]=1.0;
00670 
00671   vmd_matmultvec_4x4d(out, in, m);
00672   if (out[3]==0.0)
00673     return 0;
00674 
00675   out[3]=1.0/out[3];
00676   *objX=out[0]*out[3];
00677   *objY=out[1]*out[3];
00678   *objZ=out[2]*out[3];
00679 
00680   return 1;  
00681 #else
00682   return gluUnProject(winX, winY, winZ, model, proj, view, objX, objY, objZ);
00683 #endif
00684 }
00685 #endif
00686 
00687 
00688 static void vmd_LookAt(GLdouble eyeX,
00689                        GLdouble eyeY,
00690                        GLdouble eyeZ,
00691                        GLdouble centerX,
00692                        GLdouble centerY,
00693                        GLdouble centerZ,
00694                        GLdouble upX,
00695                        GLdouble upY,
00696                        GLdouble upZ) {
00697 #if !defined(VMDUSELIBGLU) 
00698   // initialize to identity matrix
00699   GLdouble matrix[16];
00700   vmd_mat_identity_4x4d(matrix);
00701 
00702   // now compute transform for look at point
00703   GLdouble f[3], s[3], u[3];
00704   GLdouble matrix2[16], resmat[16];
00705 
00706   f[0] = centerX - eyeX;
00707   f[1] = centerY - eyeY;
00708   f[2] = centerZ - eyeZ;
00709   vmd_vec_normalize_3d(f);
00710 
00711   // side = forward x up
00712   u[0] = upX; u[1] = upY; u[2] = upZ;
00713   vmd_cross_3d(s, f, u);
00714   vmd_vec_normalize_3d(s);
00715 
00716   // recompute orthogonal up dir: up = side x forward
00717   vmd_cross_3d(u, s, f);
00718 
00719   matrix2[ 0] = s[0];
00720   matrix2[ 4] = s[1];
00721   matrix2[ 8] = s[2];
00722   matrix2[12] = 0.0;
00723 
00724   matrix2[ 1] = u[0];
00725   matrix2[ 5] = u[1];
00726   matrix2[ 9] = u[2];
00727   matrix2[13] = 0.0;
00728 
00729   matrix2[ 2] = -f[0];
00730   matrix2[ 6] = -f[1];
00731   matrix2[10] = -f[2];
00732   matrix2[14] = 0.0;
00733 
00734   matrix2[3] = matrix2[7] = matrix2[11] = 0.0;
00735   matrix2[15] = 1.0;
00736 
00737   vmd_matmult_4x4d(resmat, matrix, matrix2);
00738   vmd_mattrans_d(resmat, -eyeX, -eyeY, -eyeZ);
00739 
00740   GLfloat tmpmat[16];
00741   for (int i=0; i<16; i++) 
00742     tmpmat[i]= (GLfloat)(resmat[i]);
00743 
00744   glLoadIdentity();
00745   glMultMatrixf(tmpmat);
00746 #else
00747   glLoadIdentity();
00748   gluLookAt(eyeX, eyeY, eyeZ, centerX, centerY, centerZ, upX, upY, upZ);
00749 #endif
00750 }
00751 
00752 
00753 #if defined(VMD_NANOHUB)
00754 bool OpenGLRenderer::init_offscreen_framebuffer(int winWidth, int winHeight) {
00755     if (_finalColorTex != 0) {
00756         glDeleteTextures(1, &_finalColorTex);
00757     }
00758     if (_finalDepthRb != 0) {
00759         glDeleteRenderbuffersEXT(1, &_finalDepthRb);
00760     }
00761     if (_finalFbo != 0) {
00762         glDeleteFramebuffersEXT(1, &_finalFbo);
00763     }
00764 
00765     // Initialize a fbo for final display.
00766     glGenFramebuffersEXT(1, &_finalFbo);
00767 
00768     glGenTextures(1, &_finalColorTex);
00769     glBindTexture(GL_TEXTURE_2D, _finalColorTex);
00770     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
00771     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
00772     glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, winWidth, winHeight, 0,
00773                  GL_RGBA, GL_UNSIGNED_BYTE, NULL);
00774 
00775     glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, _finalFbo);
00776     glGenRenderbuffersEXT(1, &_finalDepthRb);
00777     glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, _finalDepthRb);
00778     glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT24, 
00779                              winWidth, winHeight);
00780     glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
00781                               GL_TEXTURE_2D, _finalColorTex, 0);
00782     glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT,
00783                                  GL_RENDERBUFFER_EXT, _finalDepthRb);
00784 
00785     GLenum status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);
00786     if (status != GL_FRAMEBUFFER_COMPLETE_EXT) {
00787         glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
00788         glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, 0);
00789         msgWarn << "FBO Setup failed" << sendmsg;
00790         return false;
00791     }
00792     
00793     return true;
00794 }
00795 #endif
00796 
00797 
00798 void OpenGLRenderer::setup_initial_opengl_state(void) {
00799   int i; 
00800 
00801   if (getenv("VMDSIMPLEGRAPHICS") == NULL) {
00802     simplegraphics = 0; // use all available OpenGL features and extensions
00803   } else {
00804     simplegraphics = 1; // limit VMD to OpenGL ~1.0 with no extensions
00805     msgWarn << "Simple graphics mode: OpenGL 1.0, no extensions" << sendmsg;
00806   }
00807 
00808   // Create quadric objects for spheres, cylinders, and disks
00809   // Default to drawing filled objects, may be changed by the detail level
00810 #if defined(VMDUSELIBGLU)
00811   objQuadric = gluNewQuadric();
00812   pointsQuadric = gluNewQuadric();
00813   gluQuadricDrawStyle(objQuadric, (GLenum)GLU_FILL);
00814   gluQuadricDrawStyle(pointsQuadric, (GLenum)GLU_POINT);
00815 #endif
00816 
00817   // display list caching
00818   ogl_cachelistbase = 2000;
00819   ogl_cacheenabled = 0;
00820   ogl_cachedebug = 0;
00821   if (getenv("VMDCACHEDLDEBUG") != NULL) {
00822     ogl_cachedebug = 1; // enable verbose output for display list caching
00823   }
00824 
00825   wiregl = 0;          // wiregl not detected yet
00826   intelswr = 0;        // Intel SWR not detected yet
00827   immersadeskflip = 0; // Immersadesk right-eye X-axis mode off by default
00828   shearstereo = 0;     // use stereo based on eye rotation by default
00829 
00830   // initialize state caching variables so they get overwritten on 
00831   // first reference in the call to render()
00832   oglmaterialindex = -1;
00833   oglopacity = -1.0f;
00834   oglambient = -1.0f;
00835   ogldiffuse = -1.0f;
00836   oglspecular = -1.0f;
00837   oglshininess = -1.0f;
00838   ogloutline = -1.0f;
00839   ogloutlinewidth = -1.0f;
00840   ogltransmode = -1;
00841 
00842   ogl_useblendedtrans = 0;
00843   ogl_transpass = 0; 
00844   ogl_useglslshader = 0;
00845   ogl_acrobat3dcapture = 0;
00846   ogl_lightingenabled = 0;
00847   ogl_rendstateserial = 1;    // force GLSL update on 1st pass
00848   ogl_glslserial = 0;         // force GLSL update on 1st pass
00849   ogl_glsltoggle = 1;         // force GLSL update on 1st pass
00850   ogl_glslmaterialindex = -1; // force GLSL update on 1st pass
00851   ogl_glslprojectionmode = DisplayDevice::PERSPECTIVE; 
00852   ogl_glsltexturemode = 0;    // initialize GLSL projection to off
00853 
00854   // identify the rendering hardware we're using
00855   ext->find_renderer();
00856 
00857   // find all available OpenGL extensions, unless the user doesn't want us to.
00858   if (!simplegraphics) {
00859     ext->find_extensions(); 
00860   }
00861 
00862 
00863 #if 0
00864 // XXX the performance workaround aspect of this must still be tested
00865 // on Linux to verify that the existing code path is actually a benefit.
00866 
00867 // not tested on other platforms yet
00868 #if defined(__APPLE__)
00869   // Detect NVidia graphics cards, which have a semi-broken stereo 
00870   // implementation that favors rendering in stereo mode all the time, 
00871   // as the alternative is 20-50x performance hit on Linux.
00872   // XXX on MacOS X, the behavior is much more serious than just a performance
00873   // hit, they actually fail to draw/clear the back right color buffer 
00874   // when drawing to GL_BACK.
00875   if (ext->hasstereo && ext->oglrenderer == OpenGLExtensions::NVIDIA) {
00876     msgInfo << "nVidia card detected, enabling mono drawing performance workaround" << sendmsg;
00877 
00878     // force drawing in stereo even when VMD is set for mono mode
00879     ext->stereodrawforced = 1;
00880   }
00881 #endif
00882 #endif
00883 
00884 // XXX recent ATI/AMD graphics drivers are greatly improved, so this safety
00885 //     check is disabled for the time being...
00886 #if 0 && defined(__linux)
00887   // Detect ATI Linux driver and disable unsafe extensions
00888   if (ext->oglrenderer == OpenGLExtensions::ATI) {
00889     if (getenv("VMDDISABLEATILINUXWORKAROUND") == NULL) {
00890       msgInfo << "ATI Linux driver detected, limiting features to avoid driver bugs." << sendmsg;
00891       msgInfo << "  Set the environment variable VMDDISABLEATILINUXWORKAROUND" << sendmsg;
00892       msgInfo << "  to enable full functionality on a known-safe driver version." << sendmsg;
00893 
00894       simplegraphics = 1; 
00895     }
00896   }
00897 #endif
00898 
00899 #if defined(VMDWIREGL)
00900   // Detect WireGL and shut off unsupported rendering features if so.
00901   if (ext->oglrenderer == OpenGLExtensions::WIREGL ||
00902       (getenv("VMDWIREGL") != NULL)) {
00903     msgInfo << "WireGL renderer detected, disabling unsupported OpenGL features." << sendmsg;
00904     wiregl=1;
00905 
00906     // Shut off unsupported rendering features if so.
00907     ext->hastex2d = 0;
00908     ext->hastex3d = 0;
00909   }
00910 #endif
00911 
00912 #if defined(VMDINTELSWR)
00913   // Detect Intel OpenSWR and shut off unsupported rendering features if so.
00914   if (ext->oglrenderer == OpenGLExtensions::INTELSWR) {
00915     msgInfo << "Intel OpenSWR renderer detected, disabling unsupported OpenGL features." << sendmsg;
00916     intelswr=1;
00917 
00918     // the current alpha version of SWR has lots of missing functionality
00919     simplegraphics = 1; 
00920 
00921     // Shut off unsupported rendering features if so.
00922     ext->hastex2d = 0;
00923     ext->hastex3d = 0;
00924   }
00925 #endif
00926 
00927   glDepthFunc(GL_LEQUAL);
00928   glEnable(GL_DEPTH_TEST);           // use zbuffer for hidden-surface removal
00929   glClearDepth(1.0);
00930  
00931 #if 1
00932   // VMD now renormalizes all the time since non-uniform scaling 
00933   // operations must be applied for drawing ellipsoids and other 
00934   // warped geometry, and this is a final cure for people remote
00935   // displaying on machines with broken rescale normal extensions
00936   glEnable(GL_NORMALIZE);            // automatically normalize normals
00937 #else
00938   // Rescale normals, assumes they are initially normalized to begin with, 
00939   // and that only uniform scaling is applied, and non-warping modelview
00940   // matrices are used. (i.e. no shear in the modelview matrix...)
00941   // Gets rid of a square root on every normal, but still tracks
00942   // uniform scaling operations.  If not available, enable full
00943   // normalization.
00944   if (simplegraphics || wiregl || ogl_acrobat3dcapture) {
00945     // Renormalize normals if we're in 'simplegraphics' mode.
00946     // WireGL doesn't work correctly with the various normal rescaling
00947     // features and extensions, so we have to make it use GL_NORMALIZE.
00948     glEnable(GL_NORMALIZE);            // automatically normalize normals
00949   } else {
00950 #if defined(_MSC_VER) || defined(__irix) || defined(__APPLE__)
00951     // XXX The Microsoft "GDI Generic", MacOS X, and IRIX OpenGL renderers
00952     // malfunction when we use GL_RESCALE_NORMAL, so we disable it here
00953     glEnable(GL_NORMALIZE);            // automatically normalize normals
00954 #else
00955 #if defined(GL_VERSION_1_2)
00956     ext->hasrescalenormalext = 1;
00957     glEnable(GL_RESCALE_NORMAL);       // automatically rescale normals
00958 #elif defined(GL_RESCALE_NORMAL_EXT)
00959     if (ext->vmdQueryExtension("GL_RESCALE_NORMAL_EXT")) {
00960       ext->hasrescalenormalext = 1;
00961       glEnable(GL_RESCALE_NORMAL_EXT); // automatically rescale normals
00962     } else {
00963       glEnable(GL_NORMALIZE);          // automatically normalize normals
00964     }
00965 #else
00966     glEnable(GL_NORMALIZE);            // automatically normalize normals
00967 #endif
00968 #endif
00969   }  
00970 #endif
00971 
00972   // configure for dashed lines ... but initially show solid lines
00973   glLineStipple(1, 0x3333);
00974   glDisable(GL_LINE_STIPPLE);
00975 
00976   // configure the fogging characteristics ... color and position of fog
00977   // are set during the clear routine
00978   glFogi(GL_FOG_MODE, GL_EXP2);
00979   glFogf(GL_FOG_DENSITY, 0.40f);
00980 
00981   // configure the light model
00982   glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_TRUE);
00983   glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, GL_FALSE);
00984 
00985   glColorMaterial(GL_FRONT_AND_BACK, GL_DIFFUSE);
00986   glEnable(GL_COLOR_MATERIAL);       // have materials set by curr color
00987   glDisable(GL_POLYGON_SMOOTH);      // make sure not to antialias polygons
00988 
00989   // disable all lights by default
00990   for (i=0; i < DISP_LIGHTS; i++) {
00991     ogl_lightstate[i] = 0; // off by default
00992   }
00993 
00994   // disable all clipping planes by default
00995   for (i=0; i < VMD_MAX_CLIP_PLANE; i++) {
00996     ogl_clipmode[i] = 0; // off by default
00997     glDisable((GLenum) (GL_CLIP_PLANE0 + i));
00998   }
00999 
01000   // load transformation matrices on stack, initially with identity transforms
01001   glMatrixMode(GL_PROJECTION);
01002   glLoadIdentity();
01003   glMatrixMode(GL_MODELVIEW);
01004   glLoadIdentity();
01005 
01006   // generate sphere display lists
01007   glMatrixMode(GL_MODELVIEW);
01008   for (i=MIN_SPHERE_RES; i<=MAX_SPHERE_RES; i++) {
01009     GLuint solidlist = glGenLists(1);
01010     glNewList(solidlist, GL_COMPILE);
01011 #if defined(VMDUSELIBGLU)
01012     gluSphere(objQuadric, 1.0, i, i);
01013 #else
01014     vmd_DrawSphere(1.0, i, 1);
01015 #endif
01016     glEndList(); 
01017     solidSphereLists.append(solidlist);
01018 
01019     GLuint pointlist = glGenLists(1);
01020     glNewList(pointlist, GL_COMPILE);
01021 #if defined(VMDUSELIBGLU)
01022     gluSphere(pointsQuadric, 1.0, i, i);
01023 #else
01024     vmd_DrawSphere(1.0, i, 0);
01025 #endif
01026     glEndList(); 
01027     pointSphereLists.append(pointlist);
01028   }
01029 
01030   // create font display lists for use in displaying text
01031   ogl_textMat.identity();
01032 
01033   // display list for 1-pixel wide non-antialiased font rendering,
01034   // which doesn't have points at each font stroke vector endpoint
01035   font1pxListBase = glGenLists(256);
01036   glListBase(font1pxListBase);
01037   for (i=0 ; i<256 ; i++) {
01038     glNewList(font1pxListBase+i, GL_COMPILE);
01039     hersheyDrawLetterOpenGL(i, 0); // draw vector lines only
01040     glEndList();
01041   }
01042 
01043   // display list for N-pixel wide antialiased font rendering,
01044   // which has added points at each font stroke vector endpoint
01045   // to prevent "cracks" from showing up with large font sizes
01046   fontNpxListBase = glGenLists(256);
01047   glListBase(fontNpxListBase);
01048   for (i=0 ; i<256 ; i++) {
01049     glNewList(fontNpxListBase+i, GL_COMPILE);
01050     hersheyDrawLetterOpenGL(i, 1); // draw with lines+points
01051     glEndList();
01052   }
01053 
01054   // display lists are now initialized, so they must be freed when this
01055   // OpenGL context is destroyed
01056   dpl_initialized = 1;
01057 
01058 #if defined(GL_VERSION_1_1)
01059   if (!(simplegraphics || ogl_acrobat3dcapture)) {
01060     // enable vertex arrays.
01061     glEnableClientState(GL_VERTEX_ARRAY);
01062     glEnableClientState(GL_NORMAL_ARRAY);
01063     glEnableClientState(GL_COLOR_ARRAY);
01064   }
01065 #endif
01066 
01067 
01068 #if defined(GL_VERSION_1_1)
01069   if (ext->hastex2d) {
01070     int i, sz;
01071     GLint x, y;
01072 
01073     // test actual maximums for desired format
01074     glGetIntegerv(GL_MAX_TEXTURE_SIZE, &max2DtexSize);
01075     
01076     for (i=0; (sz = 1 << i) <= max2DtexSize; i++) {
01077       glTexImage2D(GL_PROXY_TEXTURE_2D, 0, GL_RGB8,
01078                    sz, sz, 0, 
01079                    GL_RGB, GL_UNSIGNED_BYTE, NULL);
01080        
01081       glGetTexLevelParameteriv(GL_PROXY_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &x);
01082       glGetTexLevelParameteriv(GL_PROXY_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT, &y);
01083     
01084       if (x > 0 && y > 0) { 
01085         max2DtexX = x;
01086         max2DtexY = y;
01087       }
01088     }
01089 
01090     if (max2DtexX > max2DtexSize)
01091       max2DtexX = max2DtexSize;
01092         
01093     if (max2DtexY > max2DtexSize)
01094       max2DtexY = max2DtexSize;
01095   } 
01096 #endif
01097 
01098 #if defined(GL_VERSION_1_2)
01099   if (ext->hastex3d) {
01100     int i, sz;
01101     GLint x, y, z;
01102 
01103     // test actual maximums for desired format
01104     max3DtexSize = 0; // until successfully queried from OpenGL
01105     max3DtexX = 0;
01106     max3DtexY = 0;
01107     max3DtexZ = 0;
01108     glGetIntegerv(GL_MAX_3D_TEXTURE_SIZE, &max3DtexSize);
01109     
01110     for (i=0; (sz = 1 << i) <= max3DtexSize; i++) {
01111       GLTEXIMAGE3D(GL_PROXY_TEXTURE_3D, 0, GL_RGB8, 
01112                    sz, sz, sz, 0, 
01113                    GL_RGB, GL_UNSIGNED_BYTE, NULL);
01114  
01115       glGetTexLevelParameteriv(GL_PROXY_TEXTURE_3D, 0, GL_TEXTURE_WIDTH,  &x);
01116       glGetTexLevelParameteriv(GL_PROXY_TEXTURE_3D, 0, GL_TEXTURE_HEIGHT, &y);
01117       glGetTexLevelParameteriv(GL_PROXY_TEXTURE_3D, 0, GL_TEXTURE_DEPTH,  &z);
01118    
01119       if (x > 0 && y > 0 && z > 0) {
01120         max3DtexX = x; 
01121         max3DtexY = y; 
01122         max3DtexZ = z; 
01123       }  
01124     }
01125 
01126     if (max3DtexX > max3DtexSize)
01127       max3DtexX = max3DtexSize;
01128         
01129     if (max3DtexY > max3DtexSize)
01130       max3DtexY = max3DtexSize;
01131 
01132     if (max3DtexZ > max3DtexSize)
01133       max3DtexZ = max3DtexSize;
01134 
01135     // disable 3-D texturing on cards that return unusable max texture sizes
01136     if (max3DtexX < 1 || max3DtexY < 1 || max3DtexZ < 1) {
01137       ext->hastex3d = 0;
01138     }
01139 
01140   }  
01141 #endif
01142 
01143 
01144 
01145 // MacOS X has had a broken implementation of GL_SEPARATE_SPECULAR_COLOR
01146 // for some time.
01147 #if defined(GL_VERSION_1_2) && !defined(__APPLE__)
01148   if (((ext->oglmajor == 1) && (ext->oglminor >= 2)) || (ext->oglmajor >= 2)) {
01149     if (ext->hastex2d || ext->hastex3d) {
01150       // Make specular color calculations follow texture mapping operations
01151       glLightModeli(GL_LIGHT_MODEL_COLOR_CONTROL, GL_SEPARATE_SPECULAR_COLOR);
01152     } else {
01153       // Do the specular color calculations at the same time as the rest 
01154       glLightModeli(GL_LIGHT_MODEL_COLOR_CONTROL, GL_SINGLE_COLOR);
01155     }
01156   }
01157 #endif
01158 
01159   ext->PrintExtensions(); 
01160 
01161 #if defined(VMDUSEOPENGLSHADER)
01162   int glslextensionsavailable=0;
01163 
01164   // Enable OpenGL programmable shading if it is available
01165   if (!(simplegraphics || ogl_acrobat3dcapture) &&
01166       ext->hasglshadinglangarb &&
01167       ext->hasglfragmentshaderarb && 
01168       ext->hasglvertexshaderarb   &&
01169       ext->hasglshaderobjectsarb &&
01170       (getenv("VMDNOGLSL") == NULL)) {
01171     glslextensionsavailable=1; // GLSL is available
01172   }
01173 
01174   if (glslextensionsavailable) {
01175     mainshader = new OpenGLShader(ext);
01176 
01177     if (mainshader) {
01178       char *shaderpath = NULL;
01179 
01180       if (getenv("VMDOGLSHADER") != NULL) {
01181         shaderpath = (char *) calloc(1, strlen(getenv("VMDOGLSHADER")) + 512);
01182         strcpy(shaderpath, getenv("VMDOGLSHADER"));
01183       } else if (getenv("VMDDIR") != NULL) {
01184         shaderpath = (char *) calloc(1, strlen(getenv("VMDDIR")) + 512);
01185         strcpy(shaderpath, getenv("VMDDIR"));
01186         strcat(shaderpath, "/shaders/vmd");
01187       } else {
01188         msgErr << "Unable to locate VMD vertex and fragment shader path, " 
01189                << "VMDDIR environment variable not set" << sendmsg;
01190         delete mainshader;
01191         mainshader = NULL;
01192       }   
01193 
01194       if (mainshader) {
01195 #if defined(_MSC_VER)
01196         // convert '/' to '\' for Windows...
01197         int i, len;
01198         len=strlen(shaderpath);
01199         for (i=0; i<len; i++) {
01200           if (shaderpath[i] == '\\') {
01201             shaderpath[i] = '/';
01202           }
01203         }
01204 #endif
01205 
01206         if (mainshader->LoadShader(shaderpath)) {
01207           mainshader->UseShader(0); // if glsl is available, turn off initially
01208           // OpenGL rendering state gets propagated on-demand at render time 
01209           // whenever ogl_renderstateserial != ogl_glslserial, thus no need to
01210           // enable the shader immediately at startup anymore.
01211         } else {
01212           msgWarn << "GPU driver failed to compile shader: " << sendmsg;
01213           msgWarn << "  " << shaderpath << sendmsg;
01214           delete mainshader;
01215           mainshader = NULL;
01216         }
01217       }
01218  
01219       if (shaderpath)
01220         free(shaderpath);
01221     }
01222     OGLERR // enable OpenGL debugging code
01223   }
01224 
01225 #if defined(VMDUSEGLSLSPHERES)
01226   // if the main shader compiled successfully, try loading up the 
01227   // sphere shader also
01228   if (mainshader) {
01229     sphereshader = new OpenGLShader(ext);
01230     char *shaderpath = NULL;
01231 
01232     if (getenv("VMDOGLSPHERESHADER") != NULL) {
01233       shaderpath = (char *) calloc(1, strlen(getenv("VMDOGLSPHERESHADER")) + 512);
01234       strcpy(shaderpath, getenv("VMDOGLSPHERESHADER"));
01235     } else if (getenv("VMDDIR") != NULL) {
01236       shaderpath = (char *) calloc(1, strlen(getenv("VMDDIR")) + 512);
01237       strcpy(shaderpath, getenv("VMDDIR"));
01238       strcat(shaderpath, "/shaders/vmdsphere");
01239     } else {
01240       msgWarn << "Unable to locate VMD sphere vertex and fragment shaders, " 
01241               << "VMDDIR environment variable not set" << sendmsg;
01242       delete sphereshader;
01243       sphereshader = NULL;
01244     }   
01245 
01246     if (sphereshader) {
01247 #if defined(_MSC_VER)
01248       // convert '/' to '\' for Windows...
01249       int i, len;
01250       len=strlen(shaderpath);
01251       for (i=0; i<len; i++) {
01252         if (shaderpath[i] == '\\') {
01253           shaderpath[i] = '/';
01254         }
01255       }
01256 #endif
01257 
01258       if (sphereshader->LoadShader(shaderpath)) {
01259         sphereshader->UseShader(0); // if glsl is available, turn off initially
01260         // OpenGL rendering state gets propagated on-demand at render time 
01261         // whenever ogl_renderstateserial != ogl_glslserial, thus no need to
01262         // enable the shader immediately at startup anymore.
01263       } else {
01264         msgWarn << "GPU driver failed to compile shader: " << sendmsg;
01265         msgWarn << "  " << shaderpath << sendmsg;
01266         delete sphereshader;
01267         sphereshader = NULL;
01268       }
01269     }
01270 
01271     if (shaderpath)
01272       free(shaderpath);
01273 
01274     OGLERR // enable OpenGL debugging code
01275   }
01276 #endif
01277 
01278 
01279 #if defined(VMDUSEGLSLSPHERESPRITES)
01280   // if the main shader compiled successfully, try loading up the 
01281   // sphere shader also
01282   if (mainshader 
01283 #if 0
01284 && getenv("VMDUSESPHERESPRITES")
01285 #endif
01286       ) {
01287     spherespriteshader = new OpenGLShader(ext);
01288     char *shaderpath = NULL;
01289 
01290     if (getenv("VMDOGLSPHERESPRITESHADER") != NULL) {
01291       shaderpath = (char *) calloc(1, strlen(getenv("VMDOGLSPHERESPRITESHADER")) + 512);
01292       strcpy(shaderpath, getenv("VMDOGLSPHERESPRITESHADER"));
01293     } else if (getenv("VMDDIR") != NULL) {
01294       shaderpath = (char *) calloc(1, strlen(getenv("VMDDIR")) + 512);
01295       strcpy(shaderpath, getenv("VMDDIR"));
01296       strcat(shaderpath, "/shaders/vmdspheresprite");
01297     } else {
01298       msgWarn << "Unable to locate VMD sphere sprite vertex and fragment shaders, " 
01299               << "VMDDIR environment variable not set" << sendmsg;
01300       delete spherespriteshader;
01301       spherespriteshader = NULL;
01302     }   
01303 
01304     if (spherespriteshader) {
01305 #if defined(_MSC_VER)
01306       // convert '/' to '\' for Windows...
01307       int i, len;
01308       len=strlen(shaderpath);
01309       for (i=0; i<len; i++) {
01310         if (shaderpath[i] == '\\') {
01311           shaderpath[i] = '/';
01312         }
01313       }
01314 #endif
01315 
01316       if (spherespriteshader->LoadShader(shaderpath)) {
01317         spherespriteshader->UseShader(0); // if glsl is available, turn off initially
01318         // OpenGL rendering state gets propagated on-demand at render time 
01319         // whenever ogl_renderstateserial != ogl_glslserial, thus no need to
01320         // enable the shader immediately at startup anymore.
01321       } else {
01322         msgWarn << "GPU driver failed to compile shader: " << sendmsg;
01323         msgWarn << "  " << shaderpath << sendmsg;
01324         delete spherespriteshader;
01325         spherespriteshader = NULL;
01326       }
01327     }
01328 
01329     if (shaderpath)
01330       free(shaderpath);
01331 
01332     OGLERR // enable OpenGL debugging code
01333   }
01334 #endif
01335 
01336   if (mainshader && sphereshader 
01337 #if defined(VMDUSEGLSLSPHERESPRITES)
01338       && ((spherespriteshader != 0) 
01339 #if 0
01340            == (getenv("VMDUSESPHERESPRITES") != NULL)
01341 #endif
01342          )
01343 #endif
01344       ) {
01345     msgInfo << "  Full GLSL rendering mode is available." << sendmsg;
01346   } else if (mainshader) {
01347     if (glslextensionsavailable) {
01348       msgWarn << "This GPU/driver is buggy, or doesn't fully implement GLSL." << sendmsg;
01349       msgWarn << "Set environment variable VMDGLSLVERBOSE for more info." << sendmsg;
01350     }
01351     msgInfo << "  Basic GLSL rendering mode is available." << sendmsg;
01352   } else {
01353     if (glslextensionsavailable) {
01354       msgWarn << "This GPU/driver is buggy, or doesn't fully implement GLSL." << sendmsg;
01355       msgWarn << "Set environment variable VMDGLSLVERBOSE for more info." << sendmsg;
01356     }
01357     msgInfo << "  GLSL rendering mode is NOT available." << sendmsg;
01358   }
01359 #endif
01360 
01361   // print information on OpenGL texturing hardware
01362   if (ext->hastex2d || ext->hastex3d) {
01363     msgInfo << "  Textures: ";
01364   
01365     if (ext->hastex2d) 
01366       msgInfo << "2-D (" << max2DtexX << "x" << max2DtexY << ")"; 
01367 
01368     if (ext->hastex2d && ext->hastex3d)
01369       msgInfo << ", ";
01370 
01371     if (ext->hastex3d) 
01372       msgInfo << "3-D (" << max3DtexX << "x" << max3DtexY << "x" << max3DtexZ << ")";
01373 
01374     if ((ext->hastex2d || ext->hastex3d) && ext->multitextureunits > 0)
01375       msgInfo << ", ";
01376 
01377     if (ext->multitextureunits > 0)
01378       msgInfo << "Multitexture (" << ext->multitextureunits << ")";
01379 
01380     msgInfo << sendmsg;
01381   }
01382 
01383   // print information about special stereo configuration
01384   if (getenv("VMDIMMERSADESKFLIP") != NULL) {
01385     immersadeskflip = 1;
01386     msgInfo << "  Enabled Immersadesk right-eye reflection stereo mode" << sendmsg;
01387   }
01388 
01389   // print information about special stereo configuration
01390   if (getenv("VMDSHEARSTEREO") != NULL) {
01391     shearstereo = 1;
01392     msgInfo << "  Enabled shear matrix stereo projection mode" << sendmsg;
01393   }
01394 
01395   OGLERR // enable OpenGL debugging code
01396 }
01397 
01398 
01399 void OpenGLRenderer::update_lists(void) {
01400   // point SphereList to the proper list
01401   ResizeArray<GLuint> *lists = (sphereMode == 
01402       ::SOLIDSPHERE) ? &solidSphereLists : &pointSphereLists;
01403   int ind = sphereRes - MIN_SPHERE_RES;
01404   if (ind < 0) 
01405     ind = 0;
01406   else if (ind >= lists->num())
01407     ind = lists->num()-1;
01408   SphereList = (*lists)[ind];
01409 }
01410 
01412 // constructor ... initialize some variables
01413 OpenGLRenderer::OpenGLRenderer(const char *nm) : DisplayDevice(nm) {
01414 #if defined(VMD_NANOHUB)
01415   _finalFbo = _finalColorTex = _finalDepthRb = 0;
01416 #endif
01417 
01418   // initialize data
01419 #if defined(VMDUSELIBGLU)
01420   objQuadric = NULL;
01421   pointsQuadric = NULL;
01422 #endif
01423 
01424 #if defined(VMDUSEOPENGLSHADER)
01425   mainshader = NULL;         // init shaders to NULL until they're loaded
01426   sphereshader = NULL;       // init shaders to NULL until they're loaded
01427   spherespriteshader = NULL; // init shaders to NULL until they're loaded
01428 #endif
01429   ext = new OpenGLExtensions;
01430 
01431   dpl_initialized = 0; // display lists need to be initialized still
01432 }
01433 
01434 
01435 // destructor
01436 OpenGLRenderer::~OpenGLRenderer(void) {
01437 #if defined(VMDUSELIBGLU)
01438   if (objQuadric != NULL)
01439     gluDeleteQuadric(objQuadric);     // delete the quadrics
01440 
01441   if (pointsQuadric != NULL)
01442     gluDeleteQuadric(pointsQuadric);  // delete the quadrics
01443 #endif
01444 
01445   delete ext;                         // delete OpenGL extensions
01446 
01447 #if defined(VMDUSEOPENGLSHADER)
01448   delete mainshader;                  // delete programmable shaders
01449   delete sphereshader;                // delete programmable shaders
01450   delete spherespriteshader;          // delete programmable shaders
01451 #endif
01452 }
01453 
01454 // prepare to free OpenGL context (should be called from subclass destructor)
01455 void OpenGLRenderer::free_opengl_ctx() {
01456   int i;
01457   GLuint tag;
01458 
01459   // delete all cached display lists
01460   displaylistcache.markUnused();
01461   while ((tag = displaylistcache.deleteUnused()) != GLCACHE_FAIL) {
01462     glDeleteLists(tag, 1);
01463   }
01464 
01465   // delete all cached textures
01466   texturecache.markUnused();
01467   while ((tag = texturecache.deleteUnused()) != GLCACHE_FAIL) {
01468     glDeleteTextures(1, &tag);
01469   }
01470 
01471   if (dpl_initialized) { 
01472     // free sphere display lists
01473     for (i=MIN_SPHERE_RES; i<=MAX_SPHERE_RES; i++) {
01474       glDeleteLists(solidSphereLists[i-MIN_SPHERE_RES], 1);
01475       glDeleteLists(pointSphereLists[i-MIN_SPHERE_RES], 1);
01476     } 
01477 
01478     // free the display lists used for the 3-D label/text font
01479     glDeleteLists(font1pxListBase, 256);
01480     glDeleteLists(fontNpxListBase, 256);
01481   }
01482 }
01483 
01484 
01486 
01487 // change current line width
01488 void OpenGLRenderer::set_line_width(int w) {
01489   if(w > 0) {
01490     glLineWidth((GLfloat)w);
01491     lineWidth = w;
01492   }
01493 }
01494 
01495 // change current line style
01496 void OpenGLRenderer::set_line_style(int s) {
01497   if(s == ::DASHEDLINE) {
01498     lineStyle = s;
01499     glEnable(GL_LINE_STIPPLE);
01500   } else {
01501     lineStyle = ::SOLIDLINE;
01502     glDisable(GL_LINE_STIPPLE);
01503   }
01504 }
01505 
01506 
01507 // change current sphere resolution
01508 void OpenGLRenderer::set_sphere_res(int r) {
01509   // avoid unnecessary display list state changes, helps avoid some serious
01510   // OpenGL performance problems on MacOS X.
01511   if (sphereRes == r)
01512     return; 
01513 
01514   if (r > 2)
01515     sphereRes = r;
01516   else
01517     sphereRes = 2;
01518 
01519   update_lists();
01520 }
01521 
01522 
01523 // change current sphere type
01524 void OpenGLRenderer::set_sphere_mode(int m) {
01525   // avoid unnecessary display list state changes, helps avoid some serious
01526   // OpenGL performance problems on MacOS X.
01527   if (sphereMode == m)
01528     return; 
01529 
01530   sphereMode = m;
01531   update_lists();
01532 }
01533 
01534 
01535 // this routine draws a cylinder from start to end, using rod_res panels,
01536 // of radius rod_radius
01537 void OpenGLRenderer::cylinder(float *end, float *start, int rod_res,
01538                               float rod_radius, float rod_top_radius) {
01539 #if !defined(VMDUSELIBGLU)
01540   vmd_DrawConic(start, end, rod_radius, rod_top_radius, rod_res);
01541 #else
01542   float R, RXY, phi, theta, lenaxis[3];
01543 
01544   // need to do some preprocessing ... find length of vector
01545   lenaxis[0] = end[0] - start[0];
01546   lenaxis[1] = end[1] - start[1];
01547   lenaxis[2] = end[2] - start[2];
01548 
01549   R = lenaxis[0]*lenaxis[0]+lenaxis[1]*lenaxis[1]+lenaxis[2]*lenaxis[2];
01550 
01551   if (R <= 0.0)
01552     return; // early exit if cylinder is of length 0;
01553 
01554   R = sqrtf(R); // evaluation of sqrt() _after_ early exit 
01555 
01556   // determine phi rotation angle, amount to rotate about y
01557   phi = acosf(lenaxis[2] / R);
01558 
01559   // determine theta rotation, amount to rotate about z
01560   RXY = sqrtf(lenaxis[0]*lenaxis[0]+lenaxis[1]*lenaxis[1]);
01561   if (RXY <= 0.0f) {
01562     theta = 0.0f;
01563   } else {
01564     theta = acosf(lenaxis[0] / RXY);
01565     if (lenaxis[1] < 0.0f)
01566       theta = (float) (2.0f * VMD_PI) - theta;
01567   }
01568 
01569   glPushMatrix(); // setup transform moving cylinder from Z-axis to position
01570   glTranslatef((GLfloat)(start[0]), (GLfloat)(start[1]), (GLfloat)(start[2]));
01571   if (theta != 0.0f)
01572     glRotatef((GLfloat) ((theta / VMD_PI) * 180.0f), 0.0f, 0.0f, 1.0f);
01573   if (phi != 0.0f)
01574     glRotatef((GLfloat) ((phi / VMD_PI) * 180.0f), 0.0f, 1.0f, 0.0f);
01575 
01576   // call utility routine to draw cylinders
01577   gluCylinder(objQuadric, (GLdouble)rod_radius, (GLdouble)rod_top_radius,
01578               (GLdouble)R, (GLint)rod_res, 1);
01579 
01580   // if this is a cone, we also draw a disk at the bottom
01581   gluQuadricOrientation(objQuadric, (GLenum)GLU_INSIDE);
01582   gluDisk(objQuadric, (GLdouble)0, (GLdouble)rod_radius, (GLint)rod_res, 1);
01583   gluQuadricOrientation(objQuadric, (GLenum)GLU_OUTSIDE);
01584 
01585   glPopMatrix(); // restore the previous transformation matrix
01586 #endif
01587 }
01588 
01589 
01590 // this routine also draws a cylinder.  However, it assumes that
01591 // the cylinder drawing command has precomputed the data.  This
01592 // uses more memory, but is faster
01593 // the data are: num == number of edges
01594 //  edges = a normal, start, and end 
01595 static void cylinder_full(int num, float *edges, int filled) {
01596   int n = num;
01597   float *start = edges;
01598 
01599   if (num < 2)
01600      return;
01601 
01602   glBegin(GL_QUAD_STRIP);
01603     while (n-- > 0) {
01604       glNormal3fv(edges);
01605       glVertex3fv(edges+6);
01606       glVertex3fv(edges+3);
01607       edges += 9;
01608     }
01609     glNormal3fv(start);  // loop back to the beginning
01610     glVertex3fv(start+6);
01611     glVertex3fv(start+3);
01612   glEnd();
01613 
01614   // and fill in the top and bottom, if needed
01615   if (filled) {
01616     float axis[3];
01617     axis[0] = start[6] - start[3];
01618     axis[1] = start[7] - start[4];
01619     axis[2] = start[8] - start[5];
01620     vec_normalize(axis);
01621 
01622     if (filled & CYLINDER_LEADINGCAP) { // do the first side
01623       n = num;            // get one side
01624       edges = start + 3;
01625       glBegin(GL_POLYGON);
01626         glNormal3fv(axis);
01627         while (--n >= 0) {
01628           glVertex3fv(edges);
01629           edges += 9;
01630         }
01631       glEnd();
01632     }
01633     if (filled & CYLINDER_TRAILINGCAP) { // do the other side
01634       n = num;          // and the other
01635       edges = start + 6;
01636       glBegin(GL_POLYGON);
01637         glNormal3fv(axis);       // I'm going the other direction, so
01638         while (--n >= 0) {
01639           glVertex3fv(edges);
01640           edges += 9;
01641         }
01642       glEnd();
01643     }
01644   }
01645 }
01646 
01647 
01649 
01650 // define a new light source ... return success of operation
01651 int OpenGLRenderer::do_define_light(int n, float *color, float *position) {
01652   int i;
01653  
01654   for(i=0; i < 3; i++)  {
01655     ogl_lightcolor[n][i] = color[i];
01656     ogl_lightpos[n][i] = position[i];
01657   }
01658   ogl_lightpos[n][3] = 0.0; // directional lights require w=0.0 otherwise
01659                             // OpenGL assumes they are positional lights.
01660   ogl_lightcolor[n][3] = 1.0;
01661 
01662   // normalize the light direction vector
01663   vec_normalize(&ogl_lightpos[n][0]); // 4th element is left alone
01664 
01665   glLightfv((GLenum)(GL_LIGHT0 + n), GL_POSITION, &ogl_lightpos[n][0]);
01666   glLightfv((GLenum)(GL_LIGHT0 + n), GL_SPECULAR, &ogl_lightcolor[n][0]);
01667   
01668   ogl_rendstateserial++; // cause GLSL cached state to update when necessary
01669   _needRedraw = 1;
01670   return TRUE;
01671 }
01672 
01673 // activate a given light source ... return success of operation
01674 int OpenGLRenderer::do_activate_light(int n, int turnon) {
01675   if (turnon) {
01676     glEnable((GLenum)(GL_LIGHT0 + n));
01677     ogl_lightstate[n] = 1;
01678   } else {
01679     glDisable((GLenum)(GL_LIGHT0 + n));
01680     ogl_lightstate[n] = 0;
01681   }
01682 
01683   ogl_rendstateserial++; // cause GLSL cached state to update when necessary
01684   _needRedraw = 1;
01685   return TRUE;
01686 }
01687 
01688 void OpenGLRenderer::loadmatrix(const Matrix4 &m) {
01689   GLfloat tmpmat[16];
01690   for (int i=0; i<16; i++) tmpmat[i]=(GLfloat)(m.mat[i]);
01691   glLoadMatrixf(tmpmat);
01692 }
01693 
01694 void OpenGLRenderer::multmatrix(const Matrix4 &m) {
01695   GLfloat tmpmat[16];
01696   for (int i=0; i<16; i++) tmpmat[i]=(GLfloat)(m.mat[i]);
01697   glMultMatrixf(tmpmat);
01698 }
01699 
01700 // virtual routines to return 2D screen coordinates, given 2D or 3D world
01701 // coordinates.  These assume the proper GL window has focus, etc.
01702 // The xy coordinates returned are absolute screen coords, relative to 
01703 // the lower left corner of the display monitor.  The returned Z coordinate
01704 // has been normalized according to its position within the view frustum
01705 // between the front and back clipping planes.  The normalized Z coordinate
01706 // is used to avoid picking points that are outside of the visible portion
01707 // of the view frustum.
01708 void OpenGLRenderer::abs_screen_loc_3D(float *loc, float *spos) {
01709   GLdouble modelMatrix[16], projMatrix[16];
01710   GLdouble pos[3];
01711   int i;
01712 
01713   // get current matrices and viewport for project call
01714   for (i=0; i<16; i++) {
01715     modelMatrix[i] = ogl_mvmatrix[i];
01716     projMatrix[i] = ogl_pmatrix[i];
01717   }
01718 
01719   // call the GLU routine to project the object coord to world coords
01720   if(!vmd_Project((GLdouble)(loc[0]), (GLdouble)(loc[1]), (GLdouble)(loc[2]),
01721      modelMatrix, projMatrix, ogl_viewport, pos, pos + 1, pos + 2)) {
01722     msgErr << "Cannot determine window position of world coordinate.";
01723     msgErr << sendmsg;
01724   } else {
01725     spos[0] = (float) (pos[0] + (float)xOrig);
01726     spos[1] = (float) (pos[1] + (float)yOrig);
01727     spos[2] = (float) (pos[2]);
01728   }
01729 }
01730 
01731 void OpenGLRenderer::abs_screen_loc_2D(float *loc, float *spos) {
01732   float newloc[3];
01733   newloc[0] = loc[0];
01734   newloc[1] = loc[1];
01735   newloc[2] = 0.0f;
01736   abs_screen_loc_3D(newloc, spos);
01737 }
01738 
01739 // Given a 3D point (pos A),
01740 // and a 2D rel screen pos point (for pos B), computes the 3D point
01741 // which goes with the second 2D point at pos B.  Result returned in B3D.
01742 // NOTE: currently, this algorithm only supports the simple case where the
01743 // eye look direction is along the Z-axis.  A more sophisticated version
01744 // requires finding the plane to which the look direction is normal, which is
01745 // assumed here to be the Z-axis (for simplicity in coding).
01746 void OpenGLRenderer::find_3D_from_2D(const float *A3D, const float *B2D,
01747                                      float *B3D) {
01748   GLdouble modelMatrix[16], projMatrix[16], w1[3], w2[3];
01749   int i;
01750   float lsx, lsy;               // used to convert rel screen -> abs
01751 
01752   // get current matrices and viewport for unproject call
01753   for (i=0; i<16; i++) {
01754     modelMatrix[i] = ogl_mvmatrix[i];
01755     projMatrix[i] = ogl_pmatrix[i];
01756   }
01757 
01758   // get window coordinates of 2D point
01759   lsx = B2D[0];
01760   lsy = B2D[1];
01761   lsx = lsx * (float)xSize;
01762   lsy = lsy * (float)ySize;
01763 
01764   // call the GLU routine to unproject the window coords to world coords
01765   if (!vmd_UnProject((GLdouble)lsx, (GLdouble)lsy, 0,
01766       modelMatrix, projMatrix, ogl_viewport, w1, w1 + 1, w1 + 2)) {
01767     msgErr << "Can't determine world coords of window position 1." << sendmsg;
01768     return;
01769   }
01770   if (!vmd_UnProject((GLdouble)lsx, (GLdouble)lsy, 1.0,
01771       modelMatrix, projMatrix, ogl_viewport, w2, w2 + 1, w2 + 2)) {
01772     msgErr << "Can't determine world coords of window position2." << sendmsg;
01773     return;
01774   }
01775 
01776   // finally, find the point where line returned as w1..w2 intersects the 
01777   // given 3D point's plane (this plane is assumed to be parallel to the X-Y
01778   // plane, i.e., with a normal along the Z-axis.  A more general algorithm
01779   // would need to find the plane which is normal to the eye look direction,
01780   // and which contains the given 3D point.)
01781   
01782   // special case: w1z = w2z ==> just return given 3D point, since there
01783   //            is either no solution, or the line is in the given plane
01784   if(w1[2] == w2[2]) {
01785     memcpy(B3D, A3D, 3*sizeof(float));
01786   } else {
01787     float relchange = (float) ((A3D[2] - w1[2]) / (w2[2] - w1[2]));
01788     B3D[0] = (float) ((w2[0] - w1[0]) * relchange + w1[0]);
01789     B3D[1] = (float) ((w2[1] - w1[1]) * relchange + w1[1]);
01790     B3D[2] = A3D[2];
01791   }
01792 }
01793 
01794 
01795 //
01796 // antialiasing and depth-cueing
01797 //
01798 
01799 // turn on antialiasing effect
01800 void OpenGLRenderer::aa_on(void) {
01801   if (inStereo == OPENGL_STEREO_STENCIL_CHECKERBOARD ||
01802       inStereo == OPENGL_STEREO_STENCIL_COLUMNS ||
01803       inStereo == OPENGL_STEREO_STENCIL_ROWS) {
01804     msgInfo << "Antialiasing must be disabled for stencil-based stereo modes."
01805 << sendmsg;
01806     msgInfo << "You may re-enable antialiasing when stereo is turned off." << sendmsg;
01807     aa_off();
01808     return;
01809   }
01810 
01811   if (aaAvailable && !aaEnabled) {
01812 #if defined(GL_ARB_multisample)
01813     if (ext->hasmultisample) {
01814       glEnable(GL_MULTISAMPLE_ARB);
01815       aaEnabled = TRUE;
01816       _needRedraw = 1;
01817       return;
01818     } 
01819 #endif
01820     // could implement accumulation buffer antialiasing here someday
01821     aaEnabled = TRUE;
01822   }
01823 }
01824 
01825 // turn off antialiasing effect
01826 void OpenGLRenderer::aa_off(void) {
01827   if(aaAvailable && aaEnabled) {
01828 #if defined(GL_ARB_multisample)
01829     if (ext->hasmultisample) {
01830       glDisable(GL_MULTISAMPLE_ARB);
01831       aaEnabled = FALSE;
01832       _needRedraw = 1;
01833       return;
01834     } 
01835 #else
01836 #endif
01837     // could implement accumulation buffer antialiasing here someday
01838     aaEnabled = FALSE;
01839   }
01840 }
01841 
01842 // turn on hardware depth-cueing
01843 void OpenGLRenderer::cueing_on(void) {
01844   if (cueingAvailable && !cueingEnabled) {
01845     glEnable(GL_FOG);
01846     cueingEnabled = TRUE;
01847     _needRedraw = 1;
01848   }
01849 }
01850 
01851 // turn off hardware depth-cueing
01852 void OpenGLRenderer::cueing_off(void) {
01853   if (cueingAvailable && cueingEnabled) {
01854     glDisable(GL_FOG);
01855     cueingEnabled = FALSE;
01856     _needRedraw = 1;
01857   }
01858 }
01859 
01860 
01861 void OpenGLRenderer::culling_on(void) {
01862   if (cullingAvailable && !cullingEnabled) {
01863     glFrontFace(GL_CCW);              // set CCW as fron face direction
01864     glPolygonMode(GL_FRONT, GL_FILL); // set front face fill mode
01865     glPolygonMode(GL_BACK,  GL_LINE); // set back face fill mode
01866     glCullFace(GL_BACK);              // set for culling back faces
01867     glEnable(GL_CULL_FACE);           // enable face culling
01868     cullingEnabled = TRUE; 
01869     _needRedraw = 1;
01870   }
01871 }
01872 
01873 void OpenGLRenderer::culling_off(void) {
01874   if (cullingAvailable && cullingEnabled) {
01875     glPolygonMode(GL_FRONT, GL_FILL); // set front face fill mode
01876     glPolygonMode(GL_BACK,  GL_FILL); // set back face fill mode
01877     glCullFace(GL_BACK);              // set for culling back faces
01878     glDisable(GL_CULL_FACE);          // disable face culling
01879     cullingEnabled = FALSE; 
01880     _needRedraw = 1;
01881   }
01882 }
01883 
01884 void OpenGLRenderer::set_background(const float *newback) {
01885   GLfloat r, g, b;
01886   r = (GLfloat)newback[0];
01887   g = (GLfloat)newback[1];
01888   b = (GLfloat)newback[2];
01889 
01890   // set fog color used for depth cueing
01891   GLfloat fogcol[4];
01892   fogcol[0] = r;
01893   fogcol[1] = g;
01894   fogcol[2] = b;
01895   fogcol[3] = 1.0;
01896 
01897   glFogfv(GL_FOG_COLOR, fogcol);
01898 
01899   // set clear color
01900   glClearColor((GLclampf)r,
01901                (GLclampf)g,
01902                (GLclampf)b, 1.0);
01903 }
01904 
01905 void OpenGLRenderer::set_backgradient(const float *topcol, 
01906                                       const float *botcol) {
01907   int i;
01908   for (i=0; i<3; i++) {
01909     ogl_backgradient[0][i] = topcol[i]; 
01910     ogl_backgradient[1][i] = botcol[i]; 
01911   }
01912   ogl_backgradient[0][3] = 1.0;
01913   ogl_backgradient[1][3] = 1.0;
01914 }
01915 
01916 // change to a different stereo mode
01917 void OpenGLRenderer::set_stereo_mode(int newMode) {
01918   if (inStereo == newMode)
01919     return;   // do nothing if current mode is same as specified mode
01920 
01921   if (inStereo == OPENGL_STEREO_STENCIL_CHECKERBOARD ||
01922       inStereo == OPENGL_STEREO_STENCIL_COLUMNS ||
01923       inStereo == OPENGL_STEREO_STENCIL_ROWS)
01924     disable_stencil_stereo(); 
01925 
01926   if (newMode == OPENGL_STEREO_STENCIL_CHECKERBOARD ||
01927       newMode == OPENGL_STEREO_STENCIL_COLUMNS ||
01928       newMode == OPENGL_STEREO_STENCIL_ROWS)
01929     enable_stencil_stereo(newMode); 
01930 
01931   inStereo = newMode;  // set new mode
01932   reshape();           // adjust the viewport width/height
01933   normal();            // adjust the viewport size/projection matrix
01934                        // this is reset again when left/right are called.
01935   clear();             // clear the screen
01936   update();            // redraw
01937 
01938   _needRedraw = 1;
01939 }
01940 
01941 // change to a different caching mode
01942 void OpenGLRenderer::set_cache_mode(int newMode) {
01943   cacheMode = newMode; // set new mode;
01944   ogl_cacheenabled = newMode;
01945 }
01946 
01947 // change to a different rendering mode
01948 void OpenGLRenderer::set_render_mode(int newMode) {
01949   if (renderMode == newMode)
01950     return;   // do nothing if current mode is same as specified mode
01951 
01952   renderMode = newMode;  // set new mode
01953 
01954   switch (renderMode) {
01955     case OPENGL_RENDER_NORMAL:
01956       ogl_useblendedtrans = 0;
01957       ogl_useglslshader = 0;
01958       ogl_acrobat3dcapture = 0;
01959       break;
01960 
01961     case OPENGL_RENDER_GLSL:
01962 #if defined(VMDUSEOPENGLSHADER)
01963       // GLSL shader state variables must now be updated to match the 
01964       // active fixed-pipeline state before/during the next rendering pass. 
01965       if (mainshader) {
01966         ogl_useblendedtrans = 1;
01967         ogl_useglslshader = 1;
01968       } else
01969 #endif
01970       {
01971         ogl_useblendedtrans = 0;
01972         ogl_useglslshader = 0;
01973         msgWarn << "OpenGL Programmable Shading not available." << sendmsg;
01974       }
01975       ogl_acrobat3dcapture = 0;
01976       break;
01977 
01978     case OPENGL_RENDER_ACROBAT3D:
01979       ogl_useblendedtrans = 0;
01980       ogl_useglslshader = 0;
01981       ogl_acrobat3dcapture = 1;
01982       break;
01983   }
01984 
01985   reshape();           // adjust the viewport width/height
01986   normal();            // adjust the viewport size/projection matrix
01987                        // this is reset again when left/right are called.
01988   clear();             // clear the screen
01989   update();            // redraw
01990 
01991   _needRedraw = 1;
01992 }
01993 
01994 
01995 // set up for normal (non-stereo) drawing.  Sets the viewport and perspective.
01996 void OpenGLRenderer::normal(void) {
01997   glViewport(0, 0, (GLsizei)xSize, (GLsizei)ySize);
01998   set_persp();
01999 
02000   // draw the background gradient if necessary
02001   draw_background_gradient();
02002 }
02003 
02004 
02005 void OpenGLRenderer::enable_stencil_stereo(int newMode) {
02006   int i;
02007   
02008   if (!ext->hasstencilbuffer) {
02009     set_stereo_mode(OPENGL_STEREO_OFF); 
02010     msgInfo << "Stencil Buffer Stereo is NOT available." << sendmsg;
02011     return;
02012   } 
02013 
02014   if (aaEnabled) {
02015     msgInfo << "Antialiasing must be disabled for stencil-based stereo modes." << sendmsg;
02016     msgInfo << "Antialiasing will be re-enabled when stereo is turned off." << sendmsg;
02017     aaPrevious = aaEnabled;
02018     aa_off();
02019   }
02020 
02021   glPushMatrix();
02022   glDisable(GL_DEPTH_TEST);
02023 
02024   glViewport(0, 0, (GLsizei)xSize, (GLsizei)ySize);
02025   glMatrixMode(GL_MODELVIEW);
02026   glLoadIdentity();
02027   glMatrixMode (GL_PROJECTION);
02028   glLoadIdentity();
02029   
02030   glOrtho(0.0, xSize, 0.0, ySize, -1.0, 1.0); // 2-D orthographic projection
02031 
02032   glMatrixMode(GL_MODELVIEW);
02033   glLoadIdentity();
02034 
02035   // clearing and configuring stencil drawing
02036   glDrawBuffer(GL_BACK);
02037 
02038   glEnable(GL_STENCIL_TEST);
02039   glClearStencil(0);
02040   glClear(GL_STENCIL_BUFFER_BIT);
02041   glStencilOp(GL_REPLACE, GL_REPLACE, GL_REPLACE); 
02042   glStencilFunc(GL_ALWAYS, 1, 1); 
02043 
02044   glColor4f(1,1,1,0); // set draw color to all 1s
02045 
02046   // According to Appendix G. of the OpenGL 1.2 Programming Guide
02047   // correct 2-D line rasterization requires placing vertices at half
02048   // pixel offsets.  This is mentioned specifically on page 677.
02049   glDisable(GL_LINE_STIPPLE); // ensure stippling is off
02050   glLineWidth(1);
02051   glBegin(GL_LINES);
02052   if (newMode == OPENGL_STEREO_STENCIL_CHECKERBOARD) {
02053     // Draw the stencil pattern on every other pixel of the window
02054     // in a checkerboard pattern, by drawing diagonal lines.
02055     for (i = -ySize; i < xSize+ySize; i += 2) {
02056       glVertex2f((GLfloat) i         + 0.5f, (GLfloat)         0.5f);
02057       glVertex2f((GLfloat) i + ySize + 0.5f, (GLfloat) ySize + 0.5f);
02058     }
02059   } else if (newMode == OPENGL_STEREO_STENCIL_COLUMNS) {
02060     // Draw the stencil pattern on every other column of the window.
02061     for (i=0; i<xSize; i+=2) {
02062       glVertex2f((GLfloat) i + 0.5f,            0.0f);
02063       glVertex2f((GLfloat) i + 0.5f, (GLfloat) ySize);
02064     }
02065   } else if (newMode == OPENGL_STEREO_STENCIL_ROWS) {
02066     // draw the stencil pattern on every other row of the window.
02067     for (i=0; i<ySize; i+=2) {
02068       glVertex2f(           0.0f, (GLfloat) i + 0.5f);
02069       glVertex2f((GLfloat) xSize, (GLfloat) i + 0.5f);
02070     }
02071   }
02072   glEnd();
02073 
02074   glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP); // disable changes to stencil buffer
02075 
02076   glEnable(GL_DEPTH_TEST);
02077   
02078   glPopMatrix();
02079 }
02080 
02081 void OpenGLRenderer::disable_stencil_stereo(void) {
02082   glDisable(GL_STENCIL_TEST);
02083   if (aaPrevious) {
02084     // XXX hack to please aa_on() so it'll reenable stereo even though
02085     // inStereo isn't quite back to normal yet.
02086     int foo = inStereo;    
02087     inStereo = OPENGL_STEREO_OFF;
02088     aa_on(); // re-enable antialiasing if we're leaving stenciling mode
02089     inStereo = foo;
02090     msgInfo << "Antialiasing re-enabled." << sendmsg;
02091   }
02092 }
02093 
02094 
02095 // set up for drawing the left eye image.  Assume always the left eye is
02096 // drawn first (so no zclear is needed before it)
02097 void OpenGLRenderer::left(void) {
02098   DisplayEye cureye = LEFTEYE;
02099   if (stereoSwap) {
02100     switch (inStereo) {
02101       case OPENGL_STEREO_HDTVSIDE:
02102       case OPENGL_STEREO_SIDE:
02103       case OPENGL_STEREO_ABOVEBELOW:
02104       case OPENGL_STEREO_QUADBUFFER:
02105       case OPENGL_STEREO_STENCIL_CHECKERBOARD:
02106       case OPENGL_STEREO_STENCIL_COLUMNS:
02107       case OPENGL_STEREO_STENCIL_ROWS:
02108       case OPENGL_STEREO_ANAGLYPH:
02109         cureye = RIGHTEYE;
02110         break;
02111     }
02112   }
02113 
02114   switch (inStereo) {
02115     case OPENGL_STEREO_HDTVSIDE:
02116       glViewport(0, 0, (GLsizei)xSize / 2, (GLsizei)ySize);
02117       set_persp(cureye);
02118       break;
02119 
02120     case OPENGL_STEREO_SIDE:
02121       glViewport(0, 0, (GLsizei)xSize / 2, (GLsizei)ySize);
02122       set_persp(cureye);
02123       break;
02124 
02125     case OPENGL_STEREO_ABOVEBELOW:
02126       glViewport(0, 0, (GLsizei)xSize, (GLsizei)ySize / 2);
02127       set_persp(cureye);
02128       break;
02129 
02130     case OPENGL_STEREO_LEFT:
02131       set_persp(LEFTEYE);
02132       break;
02133 
02134     case OPENGL_STEREO_RIGHT:
02135       set_persp(RIGHTEYE);
02136       break;
02137 
02138     case OPENGL_STEREO_QUADBUFFER:
02139       if (ext->hasstereo) {
02140         glDrawBuffer(GL_BACK_LEFT); // Z-buffer must be cleared already
02141       } else {
02142         // XXX do something since we don't support non-quad buffered modes
02143         glViewport(0, (GLint)ySize / 2, (GLsizei)xSize, (GLsizei)ySize / 2);
02144       }
02145       set_persp(cureye);
02146       break;
02147 
02148     case OPENGL_STEREO_STENCIL_CHECKERBOARD:
02149     case OPENGL_STEREO_STENCIL_COLUMNS:
02150     case OPENGL_STEREO_STENCIL_ROWS:
02151       glStencilFunc(GL_NOTEQUAL,1,1); // draws if stencil <> 1
02152       set_persp(cureye);
02153       break;
02154 
02155     case OPENGL_STEREO_ANAGLYPH:
02156       if(ext->hasstereo) {
02157         glDrawBuffer(GL_BACK_LEFT); // Z-buffer must be cleared already
02158       }
02159       // Prevailing default anaglyph format is left-eye-red
02160       glColorMask(GL_TRUE, GL_FALSE, GL_FALSE, GL_TRUE); 
02161       set_persp(cureye);
02162       break;
02163 
02164     default:
02165       normal(); // left called even though we're non-stereo
02166 // not tested on other platforms yet
02167 #if defined(__APPLE__)
02168       if (ext->hasstereo && ext->stereodrawforced)
02169         glDrawBuffer(GL_BACK_LEFT); // draw to back-left
02170 #endif
02171       break;
02172   }
02173 
02174   // draw the background gradient if necessary
02175   draw_background_gradient();
02176 }
02177 
02178 
02179 // set up for drawing the right eye image.  Assume always the right eye is
02180 // drawn last (so a zclear IS needed before it)
02181 void OpenGLRenderer::right(void) {
02182   DisplayEye cureye = RIGHTEYE;
02183   if (stereoSwap) {
02184     switch (inStereo) {
02185       case OPENGL_STEREO_HDTVSIDE:
02186       case OPENGL_STEREO_SIDE:
02187       case OPENGL_STEREO_ABOVEBELOW:
02188       case OPENGL_STEREO_QUADBUFFER:
02189       case OPENGL_STEREO_STENCIL_CHECKERBOARD:
02190       case OPENGL_STEREO_STENCIL_COLUMNS:
02191       case OPENGL_STEREO_STENCIL_ROWS:
02192       case OPENGL_STEREO_ANAGLYPH:
02193         cureye = LEFTEYE;
02194         break;
02195     }
02196   }
02197 
02198   switch (inStereo) {
02199     case OPENGL_STEREO_HDTVSIDE:
02200       glViewport((GLsizei)xSize / 2, 0, (GLsizei)xSize / 2, (GLsizei)ySize);
02201       set_persp(cureye);
02202       break;
02203 
02204     case OPENGL_STEREO_SIDE:
02205       glViewport((GLsizei)xSize / 2, 0, (GLsizei)xSize / 2, (GLsizei)ySize);
02206       set_persp(cureye);
02207       break;
02208 
02209     case OPENGL_STEREO_ABOVEBELOW:
02210       glViewport(0, (GLsizei)ySize / 2, (GLsizei)xSize, (GLsizei)ySize / 2);
02211       set_persp(cureye);
02212       break;
02213 
02214     case OPENGL_STEREO_LEFT:
02215     case OPENGL_STEREO_RIGHT:
02216       // no need to do anything, already done in call to left
02217       break;
02218 
02219     case OPENGL_STEREO_QUADBUFFER:
02220       if (ext->hasstereo) {
02221         glDepthMask(GL_TRUE);  // make Z-buffer writable
02222 #if defined(__APPLE__)
02223         // XXX This hack is required by MacOS X because their 
02224         // Quadro 4500 stereo drivers are broken such that the 
02225         // clear on both right/left buffers doesn't actually work.
02226         // This explicitly forces a second clear on the back right buffer.
02227         glDrawBuffer(GL_BACK_RIGHT);
02228         glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
02229 #else
02230         // all other platforms work fine
02231         glClear(GL_DEPTH_BUFFER_BIT);
02232 #endif
02233         glDrawBuffer(GL_BACK_RIGHT);
02234       } else {
02235         // XXX do something since we don't support non-quad buffered modes
02236         glViewport(0, 0, (GLsizei)xSize, (GLsizei)ySize / 2);
02237       }
02238       set_persp(cureye);
02239       break;
02240 
02241     case OPENGL_STEREO_STENCIL_CHECKERBOARD:
02242     case OPENGL_STEREO_STENCIL_COLUMNS:
02243     case OPENGL_STEREO_STENCIL_ROWS:
02244       glDepthMask(GL_TRUE);  // make Z-buffer writable
02245       glClear(GL_DEPTH_BUFFER_BIT);
02246       glStencilFunc(GL_EQUAL,1,1); // draws if stencil <> 0
02247       set_persp(cureye);
02248       break;
02249 
02250     case OPENGL_STEREO_ANAGLYPH:
02251       if(ext->hasstereo) {
02252         glDrawBuffer(GL_BACK_RIGHT);
02253       }
02254 
02255       // Prevailing default anaglyph format is left-eye-red
02256 #if 1
02257       // Use both green and blue components on right-eye, to yield
02258       // a more "full color" effect for red-blue and red-cyan glasses
02259       glColorMask(GL_FALSE, GL_TRUE, GL_TRUE, GL_TRUE); 
02260 #else
02261       // Use blue channel only for reduced ghosting with cheap filters
02262       glColorMask(GL_FALSE, GL_FALSE, GL_TRUE, GL_TRUE); 
02263 #endif
02264       glDepthMask(GL_TRUE);  // make Z-buffer writable
02265       glClear(GL_DEPTH_BUFFER_BIT);
02266       set_persp(cureye);
02267       break;
02268 
02269     default:
02270       normal(); // right called even though we're non-stereo
02271 // not tested on other platforms yet
02272 #if defined(__APPLE__)
02273       if (ext->hasstereo && ext->stereodrawforced)
02274         glDrawBuffer(GL_BACK_RIGHT); // draw to back-right
02275 #endif
02276       break;
02277   }
02278 
02279   // draw the background gradient if necessary
02280   draw_background_gradient();
02281 }
02282 
02283 
02284 // set the current perspective, based on the eye position and where we
02285 // are looking.
02286 void OpenGLRenderer::set_persp(DisplayEye my_eye) {
02287   // define eye and look at some point.  Assumes up vector = (0,1,0)
02288   GLdouble ep[3];
02289   switch (my_eye) {
02290     case LEFTEYE:
02291       ep[0] = eyePos[0] - eyeSepDir[0];
02292       ep[1] = eyePos[1] - eyeSepDir[1];
02293       ep[2] = eyePos[2] - eyeSepDir[2];
02294       DisplayDevice::left();
02295       break;
02296     case RIGHTEYE: 
02297       ep[0] = eyePos[0] + eyeSepDir[0];
02298       ep[1] = eyePos[1] + eyeSepDir[1];
02299       ep[2] = eyePos[2] + eyeSepDir[2];
02300       DisplayDevice::right();
02301       break;
02302 
02303     case NOSTEREO:
02304     default:
02305       ep[0] = eyePos[0];
02306       ep[1] = eyePos[1];
02307       ep[2] = eyePos[2];
02308       DisplayDevice::normal();
02309       break;
02310   }
02311 
02312   // setup camera system and projection transformations
02313   if (projection() == PERSPECTIVE) {
02314     ogl_glslprojectionmode = DisplayDevice::PERSPECTIVE; 
02315 
02316     if (shearstereo) {
02317       // XXX almost ready for prime time, when testing is done we may
02318       // make shear stereo the default and eye rotation a backwards 
02319       // compatibility option.
02320       // Use the "frustum shearing" method for creating a stereo view.  
02321       // The frustum shearing method is preferable to eye rotation in general.
02322 
02323       // Calculate the eye shift (half eye separation distance)
02324       // XXX hack, needs to be more general
02325       float eyeshift = float(ep[0] - eyePos[0]);
02326 
02327       glMatrixMode(GL_PROJECTION);
02328       glLoadIdentity();
02329       // Shifts viewing frustum horizontally in the image plane
02330       // according to the stereo eye separation if rendering in stereo.
02331       // XXX hack, the parameterization of this projection still 
02332       // needs work, but the fact that it incorporates eyeDist is nice.
02333       glFrustum((GLdouble)cpLeft  + (eyeshift * nearClip / eyeDist),
02334                 (GLdouble)cpRight + (eyeshift * nearClip / eyeDist),
02335                 (GLdouble)cpDown, 
02336                 (GLdouble)cpUp,
02337                 (GLdouble)nearClip, 
02338                 (GLdouble)farClip);
02339 
02340       // Shift the eye position horizontally by half the eye separation
02341       // distance if rendering in stereo.
02342       glTranslatef(-eyeshift, 0.0, 0.0); 
02343 
02344       glMatrixMode(GL_MODELVIEW);
02345       // set modelview identity and then applies transform
02346       vmd_LookAt(eyePos[0], eyePos[1], eyePos[2],
02347                  (GLdouble)(eyePos[0] + eyeDir[0]),
02348                  (GLdouble)(eyePos[1] + eyeDir[1]),
02349                  (GLdouble)(eyePos[2] + eyeDir[2]),
02350                  (GLdouble)(upDir[0]),
02351                  (GLdouble)(upDir[1]),
02352                  (GLdouble)(upDir[2]));
02353     } else {
02354       // Use the "eye rotation" method for creating a stereo view.  
02355       // The frustum shearing method would be preferable.
02356       // XXX this implementation is not currently using the eyeDist
02357       // parameter, though it probably should.
02358       glMatrixMode(GL_PROJECTION);
02359       glLoadIdentity();
02360       glFrustum((GLdouble)cpLeft,  (GLdouble)cpRight,  (GLdouble)cpDown,
02361                 (GLdouble)cpUp,   (GLdouble)nearClip, (GLdouble)farClip);
02362 
02363       // Reflect the X axis of the right eye for the new LCD panel immersadesks
02364       // XXX experimental hack that needs more work to get lighting
02365       // completely correct for the Axes, Title Screen, etc.
02366       if (immersadeskflip && my_eye == RIGHTEYE) {
02367         // Scale the X axis by -1 in the GL_PROJECTION matrix
02368         glScalef(-1, 1, 1);
02369       }
02370 
02371       glMatrixMode(GL_MODELVIEW);
02372       // set modelview identity and then applies transform
02373       vmd_LookAt(ep[0], ep[1], ep[2],
02374                  (GLdouble)(eyePos[0] + eyeDir[0]),
02375                  (GLdouble)(eyePos[1] + eyeDir[1]),
02376                  (GLdouble)(eyePos[2] + eyeDir[2]),
02377                  (GLdouble)(upDir[0]),
02378                  (GLdouble)(upDir[1]),
02379                  (GLdouble)(upDir[2]));
02380     }
02381   } else { // ORTHOGRAPHIC
02382     ogl_glslprojectionmode = DisplayDevice::ORTHOGRAPHIC; 
02383     glMatrixMode(GL_PROJECTION);
02384     glLoadIdentity();
02385 
02386     glOrtho(-0.25 * vSize * Aspect, 0.25 * vSize * Aspect,
02387             -0.25 * vSize,          0.25 * vSize,
02388             nearClip, farClip);
02389 
02390     // Use the "eye rotation" method for creating a stereo view.  
02391     // The frustum shearing method won't work with orthographic 
02392     // views since the eye rays are parallel, so the rotation method 
02393     // is ok in this case.
02394     glMatrixMode(GL_MODELVIEW);
02395     // set modelview identity and then applies transform
02396     vmd_LookAt(ep[0], ep[1], ep[2],
02397                (GLdouble)(eyePos[0] + eyeDir[0]),
02398                (GLdouble)(eyePos[1] + eyeDir[1]),
02399                (GLdouble)(eyePos[2] + eyeDir[2]),
02400                (GLdouble)(upDir[0]),
02401                (GLdouble)(upDir[1]),
02402                (GLdouble)(upDir[2]));
02403   }
02404 
02405   // update the cached transformation matrices for use in text display, etc.
02406   glGetFloatv(GL_PROJECTION_MATRIX, ogl_pmatrix);
02407   glGetFloatv(GL_MODELVIEW_MATRIX, ogl_mvmatrix);
02408   glGetIntegerv(GL_VIEWPORT, ogl_viewport);
02409   ogl_textMat.identity();
02410   ogl_textMat.multmatrix(ogl_pmatrix);
02411   ogl_textMat.multmatrix(ogl_mvmatrix);
02412 }
02413 
02414 
02415 // prepare to draw a 3D image
02416 int OpenGLRenderer::prepare3D(int do_clear) {
02417   if (do_clear) {
02418     clear();
02419   } else {
02420     glDepthMask(GL_TRUE);  // make Z-buffer writable
02421     glClear(GL_DEPTH_BUFFER_BIT);
02422   }
02423 
02424   // invalidate the OpenGL material index cache since a new frame is
02425   // being drawn and the material state for the previous index may 
02426   // have changed.  
02427   oglmaterialindex = -1;
02428 
02429   // start a new frame, marking all cached IDs as "unused"
02430   displaylistcache.markUnused();
02431   texturecache.markUnused();
02432 
02433   return TRUE; // must return true for normal (non file-based) renderers
02434 }
02435 
02436 
02437 // prepare to draw opaque objects
02438 int OpenGLRenderer::prepareOpaque(void) {
02439   if (ogl_useblendedtrans) {
02440     glDepthMask(GL_TRUE); // make Z-buffer writable
02441     ogl_transpass = 0;
02442   }
02443 
02444   return 1;
02445 }
02446 
02447 // prepare to draw transparent objects
02448 int OpenGLRenderer::prepareTrans(void) {
02449   if (ogl_useblendedtrans) {
02450     glDepthMask(GL_FALSE); // make Z-buffer read-only while drawing trans objs
02451     ogl_transpass = 1;
02452     return 1;
02453   }
02454 
02455   return 0;
02456 }
02457 
02458 // clear the display
02459 void OpenGLRenderer::clear(void) {
02460   // clear the whole viewport, not just one side 
02461   switch (inStereo) {
02462     case OPENGL_STEREO_HDTVSIDE:
02463     case OPENGL_STEREO_SIDE:
02464     case OPENGL_STEREO_ABOVEBELOW:
02465     case OPENGL_STEREO_QUADBUFFER:
02466     case OPENGL_STEREO_ANAGLYPH:
02467       glViewport(0, 0, (GLsizei)xSize, (GLsizei)ySize);
02468       break;
02469   }
02470 
02471   glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);    // reset color mask 
02472   glDepthMask(GL_TRUE);                               // make Z-buffer writable
02473   glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Clear color/depth bufs
02474 
02475 // not tested on other platforms yet
02476 #if defined(__APPLE__)
02477   if (ext->hasstereo && ext->stereodrawforced) {
02478     glDrawBuffer(GL_BACK_RIGHT);
02479     glClear(GL_COLOR_BUFFER_BIT); // force separate clear of right buffer
02480     glDrawBuffer(GL_BACK);
02481   }
02482 #endif
02483 }
02484 
02485 
02486 // draw the background gradient
02487 void OpenGLRenderer::draw_background_gradient(void) {
02488   // if the background mode is set for gradient, then draw the gradient
02489   // note: this must be done immediately after clearing the viewport
02490   if (backgroundmode != 0) {
02491     int i;
02492 
02493     // disable all clipping planes by default
02494     for (i=0; i < VMD_MAX_CLIP_PLANE; i++) {
02495       ogl_clipmode[i] = 0; // off by default
02496       glDisable((GLenum) (GL_CLIP_PLANE0 + i));
02497     }
02498 
02499     glDisable(GL_LIGHTING);           // disable lighting
02500     ogl_lightingenabled=0;            // update state var
02501 #if defined(VMDUSEOPENGLSHADER)
02502     if (mainshader && ogl_useglslshader) {
02503       mainshader->UseShader(0);       // use fixed-func pipeline
02504     }
02505 #endif
02506     glDisable(GL_DEPTH_TEST);         // disable depth test
02507     glDepthMask(GL_FALSE);            // make Z-buffer read-only
02508 
02509     // turn off any transparent rendering state
02510     glDisable(GL_POLYGON_STIPPLE);    // make sure stippling is disabled
02511     glDisable(GL_BLEND);              // disable blending
02512 
02513     glMatrixMode(GL_MODELVIEW);       // save existing transformation state
02514     glPushMatrix();
02515     glLoadIdentity();                 // prepare for 2-D orthographic drawing
02516 
02517     glMatrixMode (GL_PROJECTION);     // save existing transformation state
02518     glPushMatrix();
02519     glLoadIdentity();
02520     glOrtho(0.0, 1.0, 0.0, 1.0, -1.0, 1.0); // 2-D orthographic projection
02521 
02522     glMatrixMode(GL_MODELVIEW);
02523     glPushMatrix();
02524     glLoadIdentity();                 // add one more modelview
02525 
02526     // draw the background polygon
02527     glBegin(GL_QUADS);
02528       glColor3fv(&ogl_backgradient[1][0]);
02529       glVertex2f(0.0f, 0.0f);
02530       glColor3fv(&ogl_backgradient[1][0]);
02531       glVertex2f(1.0f, 0.0f);
02532       glColor3fv(&ogl_backgradient[0][0]);
02533       glVertex2f(1.0f, 1.0f);
02534       glColor3fv(&ogl_backgradient[0][0]);
02535       glVertex2f(0.0f, 1.0f);
02536     glEnd();
02537 
02538     glPopMatrix();                     // pop off top modelview
02539 
02540     glMatrixMode (GL_PROJECTION);
02541     glPopMatrix();                     // restore projection transform state
02542 
02543     glMatrixMode(GL_MODELVIEW);
02544     glPopMatrix();                     // restore modelview transform state
02545 
02546     glEnable(GL_DEPTH_TEST);           // restore depth testing
02547     glDepthMask(GL_TRUE);              // make Z-buffer writeable
02548     glEnable(GL_LIGHTING);             // restore lighting
02549     ogl_lightingenabled=1;             // update state var
02550 #if defined(VMDUSEOPENGLSHADER)
02551     if (mainshader && ogl_useglslshader) {
02552       mainshader->UseShader(1);        // re-enable glsl mainshader
02553     }
02554 #endif
02555   }
02556 }
02557 
02558 
02559 //**********************  the rendering routine  ***********************
02560 //* This scans the given command list until the end, doing the commands
02561 //* in the order they appear
02562 //**********************************************************************
02563 void OpenGLRenderer::render(const VMDDisplayList *cmdList) {
02564   char *cmdptr = NULL;  // ptr to current display command data
02565   int tok;              // what display command was encountered
02566   _needRedraw = 0;      // reset the flag now that we are drawing
02567 
02568   // early exit if any of these conditions are true. 
02569   if (!cmdList) 
02570     return;
02571 
02572   if (ogl_useblendedtrans) {
02573     if (ogl_transpass) {
02574       // skip rendering mostly Opaque objects on transparent pass
02575       if (cmdList->opacity > 0.50) 
02576         return;
02577     } else {
02578       // skip rendering mostly transparent objects on opaque pass
02579       if (cmdList->opacity <= 0.50)
02580         return;
02581     }
02582   } else {
02583     if (cmdList->opacity < 0.0625)
02584       return;
02585   }
02586 
02587   // if we're rendering for Acrobat3D capture, emit materials and other
02588   // state changes at every opportunity, caching next to nothing by 
02589   // invalidating materials on every object we draw
02590   if (ogl_acrobat3dcapture) {
02591     oglmaterialindex = -1;
02592     oglambient   = -1;
02593     ogldiffuse   = -1;
02594     oglspecular  = -1;
02595     oglshininess = -1;
02596     ogloutline = -1;
02597     ogloutlinewidth = -1;
02598     ogltransmode = -1;
02599   } 
02600 
02601   //
02602   // set the material - only changing those items that have been updated.
02603   //
02604   if (oglmaterialindex != cmdList->materialtag) {
02605     float matbuf[4];
02606     matbuf[3] = 1.0f; 
02607     int recalcambientlights = 0;
02608     int recalcdiffuselights = 0;
02609 
02610     oglmaterialindex = cmdList->materialtag;
02611     if (oglopacity != cmdList->opacity) {
02612       oglopacity = cmdList->opacity; // update for next time through
02613 
02614       if (ogl_useblendedtrans) {
02615         glDisable(GL_POLYGON_STIPPLE);   
02616         if (oglopacity > 0.999) {
02617           // disable alpha-blended transparency
02618           glDisable(GL_BLEND);
02619         } else {
02620           glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
02621           glEnable(GL_BLEND);
02622         }
02623       } else {
02624         // disable alpha-blended transparency
02625         glDisable(GL_BLEND);
02626 
02627         // use stipple-based transparency
02628         if (oglopacity > 0.9375) {  
02629           glDisable(GL_POLYGON_STIPPLE);   
02630         } else {
02631           // here's our transparency: opacity < 0.9375  -> transparent
02632           if (oglopacity > 0.875) 
02633             glPolygonStipple(ninesixteentone);               
02634           else if (oglopacity > 0.75) 
02635             glPolygonStipple(seveneighthtone);               
02636           else if (oglopacity > 0.5) 
02637             glPolygonStipple(threequartertone);               
02638           else if (oglopacity > 0.25)
02639             glPolygonStipple(halftone);               
02640           else if (oglopacity > 0.125)
02641             glPolygonStipple(quartertone);               
02642           else if (oglopacity > 0.0625)
02643             glPolygonStipple(eighthtone);               
02644           else 
02645             return; // skip rendering the geometry if entirely transparent
02646     
02647           glEnable(GL_POLYGON_STIPPLE);                
02648         }
02649       }
02650     }
02651 
02652     if (ogloutline != cmdList->outline) { 
02653       ogloutline = cmdList->outline;
02654     }
02655 
02656     if (ogloutlinewidth != cmdList->outlinewidth) { 
02657       ogloutlinewidth = cmdList->outlinewidth;
02658     }
02659 
02660     if (ogltransmode != (int) cmdList->transmode) { 
02661       ogltransmode = (int) cmdList->transmode;
02662     }
02663 
02664     if (oglambient != cmdList->ambient) { 
02665       oglambient = cmdList->ambient;
02666       recalcambientlights = 1;  // force recalculation of ambient lighting
02667       matbuf[0] = matbuf[1] = matbuf[2] = oglambient; 
02668       glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, matbuf);
02669     }
02670 
02671     if (ogldiffuse != cmdList->diffuse) { 
02672       ogldiffuse = cmdList->diffuse;
02673       recalcdiffuselights = 1;  // force recalculation of diffuse lighting
02674       matbuf[0] = matbuf[1] = matbuf[2] = ogldiffuse; 
02675       glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, matbuf);
02676     }
02677 
02678     if (oglspecular != cmdList->specular) { 
02679       oglspecular = cmdList->specular;
02680       matbuf[0] = matbuf[1] = matbuf[2] = oglspecular; 
02681       glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, matbuf);
02682     }
02683 
02684     if (oglshininess != cmdList->shininess) {
02685       oglshininess = cmdList->shininess;
02686   
02687       // clamp shininess parameter to what OpenGL 1.x can deal with
02688       // XXX there are new OpenGL extensions that allow a broader range
02689       // of Phong exponents.
02690       glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, 
02691                   (GLfloat) (oglshininess < 128.0f) ? oglshininess : 128.0f);
02692     }
02693  
02694     // change lighting to match new diffuse/ambient factors
02695     if (recalcambientlights) { 
02696       for (int z=0; z<DISP_LIGHTS; z++) {
02697         GLfloat d[4];
02698         d[0] = ogl_lightcolor[z][0] * oglambient;
02699         d[1] = ogl_lightcolor[z][1] * oglambient;
02700         d[2] = ogl_lightcolor[z][2] * oglambient;
02701         d[3] = 1.0;
02702         glLightfv((GLenum)(GL_LIGHT0 + z), GL_AMBIENT, d);
02703       }
02704     }
02705  
02706     if (recalcdiffuselights) { 
02707       for (int z=0; z<DISP_LIGHTS; z++) {
02708         GLfloat d[4];
02709         d[0] = ogl_lightcolor[z][0] * ogldiffuse;
02710         d[1] = ogl_lightcolor[z][1] * ogldiffuse;
02711         d[2] = ogl_lightcolor[z][2] * ogldiffuse;
02712         d[3] = 1.0;
02713         glLightfv((GLenum)(GL_LIGHT0 + z), GL_DIFFUSE, d);
02714       }
02715     }
02716   }
02717   // 
02718   // end material processing code for fixed-function OpenGL pipeline
02719   //
02720 
02721   // XXX shouldn't be testing this every rep, but for now this works ok 
02722   ogl_fogmode = 0; // fogmode for shaders
02723 
02724   if (cueingEnabled) {
02725     switch (cueMode) {
02726       case CUE_LINEAR: 
02727         glFogi(GL_FOG_MODE, GL_LINEAR);
02728         ogl_fogmode = 1;
02729         break;
02730   
02731       case CUE_EXP:
02732         glFogi(GL_FOG_MODE, GL_EXP);
02733         ogl_fogmode = 2;
02734         break;
02735   
02736       case CUE_EXP2:
02737         glFogi(GL_FOG_MODE, GL_EXP2);
02738         ogl_fogmode = 3;
02739         break;
02740 
02741       case NUM_CUE_MODES:
02742         // this should never happen
02743         break;
02744     }
02745 
02746     glFogf(GL_FOG_DENSITY, (GLfloat) get_cue_density());
02747     glFogf(GL_FOG_START,   (GLfloat) get_cue_start());
02748     glFogf(GL_FOG_END,     (GLfloat) get_cue_end());
02749   }
02750 
02751 #if defined(VMDUSEOPENGLSHADER)
02752   // setup programmable shader for this object
02753   if (mainshader) {
02754     if (ogl_useglslshader) {
02755       mainshader->UseShader(1); // if glsl is available and enabled, use it
02756   
02757       if ((ogl_glslmaterialindex != cmdList->materialtag) || ogl_glsltoggle) {
02758         ogl_glslmaterialindex = cmdList->materialtag;
02759         ogl_glsltoggle = 0;
02760         update_shader_uniforms(mainshader, 1);
02761       }
02762     } else {
02763       mainshader->UseShader(0); // if glsl is available but disabled, turn it off
02764     }
02765   }
02766 #endif
02767 
02768   // save transformation matrix
02769   glMatrixMode(GL_MODELVIEW);
02770   glPushMatrix();
02771   multmatrix(cmdList->mat);
02772 
02773   // set up text matrices
02774   GLfloat textsize = 1;
02775   Matrix4 textMat(ogl_textMat);
02776   textMat.multmatrix(cmdList->mat);
02777   
02778   // XXX Display list caching begins here
02779   GLuint ogl_cachedid = 0;    // reset OpenGL display list ID for cached list
02780   int ogl_cachecreated = 0;  // reset display list creation flag
02781   int ogl_cacheskip;
02782 
02783   // Disable display list caching if GLSL is enabled or we encounter
02784   // a non-cacheable representation (such as an animating structure).
02785   ogl_cacheskip = (cmdList->cacheskip || ogl_useglslshader);
02786 
02787   // enable/disable clipping planes
02788   for (int cp=0; cp<VMD_MAX_CLIP_PLANE; cp++) {
02789     // don't cache 'on' state since the parameters will likely differ,
02790     // just setup the clip plane from the new state
02791     if (cmdList->clipplanes[cp].mode) {
02792       GLdouble cpeq[4];
02793       cpeq[0] = cmdList->clipplanes[cp].normal[0];
02794       cpeq[1] = cmdList->clipplanes[cp].normal[1];
02795       cpeq[2] = cmdList->clipplanes[cp].normal[2];
02796   
02797       // Convert specification to OpenGL plane equation
02798       cpeq[3] = 
02799       -(cmdList->clipplanes[cp].normal[0] * cmdList->clipplanes[cp].center[0] +
02800         cmdList->clipplanes[cp].normal[1] * cmdList->clipplanes[cp].center[1] +
02801         cmdList->clipplanes[cp].normal[2] * cmdList->clipplanes[cp].center[2]);
02802       glClipPlane((GLenum) (GL_CLIP_PLANE0 + cp), cpeq);
02803       glEnable((GLenum) (GL_CLIP_PLANE0 + cp)); 
02804 
02805       // XXX if the clipping plane mode is set for rendering
02806       // capped clipped solids, we will have to perform several
02807       // rendering passes using the stencil buffer and Z-buffer 
02808       // in order to get the desired results.
02809       // http://www.nigels.com/research/wscg2002.pdf 
02810       // http://citeseer.ist.psu.edu/stewart02lineartime.html
02811       // http://citeseer.ist.psu.edu/stewart98improved.html
02812       // http://www.sgi.com/software/opengl/advanced97/notes/node10.html
02813       // http://www.opengl.org/resources/tutorials/sig99/advanced99/notes/node21.html
02814       // http://www.ati.com/developer/sdk/rage128sdk/OpenGL/Samples/Rage128StencilCap.html
02815       // The most common algorithm goes something like what is described here:
02816       //   0) clear stencil/color/depth buffers
02817       //   1) disable color buffer writes
02818       //   2) render clipping plane polygon writing to depth buffer
02819       //   3) disable depth buffer writes
02820       //   4) set stencil op to increment when depth test passes
02821       //   5) draw molecule with glCullFace(GL_BACK)
02822       //   6) set stencil op to decrement when depth test passes
02823       //   7) draw molecule with glCullFace(GL_FRONT)
02824       //   8) clear depth buffer
02825       //   9) enable color buffer writes 
02826       //  10) set stencil function to GL_EQUAL of 1
02827       //  11) draw clipping plane polygon with appropriate materials
02828       //  12) disable stencil buffer
02829       //  13) enable OpenGL clipping plane
02830       //  14) draw molecule
02831     } else {
02832       // if its already off, no need to disable it again.
02833       if (ogl_clipmode[cp] != cmdList->clipplanes[cp].mode) {
02834         glDisable((GLenum) (GL_CLIP_PLANE0 + cp)); 
02835       }
02836     }
02837 
02838     // update clip mode cache
02839     ogl_clipmode[cp] = cmdList->clipplanes[cp].mode;
02840   }
02841 
02842   // initialize text offset variables.  These values should never be set in one
02843   // display list and applied in another, so we make them local variables here
02844   // rather than OpenGLRenderer state variables.
02845   float textoffset_x = 0, textoffset_y = 0;
02846 
02847   // Compute periodic image transformation matrices
02848   ResizeArray<Matrix4> pbcImages;
02849   find_pbc_images(cmdList, pbcImages);
02850   int npbcimages = pbcImages.num();
02851 
02852   // Retreive instance image transformation matrices
02853   ResizeArray<Matrix4> instanceImages;
02854   find_instance_images(cmdList, instanceImages);
02855   int ninstances = instanceImages.num();
02856 
02857 for (int pbcimage = 0; pbcimage < npbcimages; pbcimage++) {
02858   glPushMatrix();
02859   multmatrix(pbcImages[pbcimage]);
02860 
02861 for (int instanceimage = 0; instanceimage < ninstances; instanceimage++) {
02862   glPushMatrix();
02863   multmatrix(instanceImages[instanceimage]);
02864 
02865   if (ogl_cachedebug) {
02866     msgInfo << "Rendering scene: cache enable=" << ogl_cacheenabled 
02867             << ", created=" << ogl_cachecreated << ", serial=" << (int)cmdList->serial
02868             << ", id=" << (int)ogl_cachedid << ", skip=" << ogl_cacheskip << sendmsg;
02869   }
02870 
02871   // find previously cached display list for this object
02872   if (ogl_cacheenabled && !ogl_cacheskip) {
02873     ogl_cachedid = displaylistcache.markUsed(cmdList->serial);
02874 
02875     // add to the cache and regenerate if we didn't find it
02876     if (ogl_cachedid == GLCACHE_FAIL) {
02877       ogl_cachedid = glGenLists(1);      
02878       displaylistcache.encache(cmdList->serial, ogl_cachedid);
02879 
02880       // create the display list, and execute it.
02881       glNewList(ogl_cachedid, GL_COMPILE_AND_EXECUTE);
02882       ogl_cachecreated = 1; // a new display list was created 
02883     } 
02884   }
02885 
02886   // XXX Draw OpenGL geometry only when caching is disabled or when
02887   //     we have new geometry to cache
02888   if ((!ogl_cacheenabled) || ogl_cacheskip || (ogl_cacheenabled && ogl_cachecreated)) {
02889 
02890   // scan through the list, getting each command and executing it, until
02891   // the end of commands token is found
02892   VMDDisplayList::VMDLinkIter cmditer;
02893   cmdList->first(&cmditer);
02894   while((tok = cmdList->next(&cmditer, cmdptr)) != DLASTCOMMAND) {
02895     OGLERR // enable OpenGL debugging code
02896 
02897     switch (tok) {
02898       case DPOINT:
02899         // plot a point at the given position
02900         glBegin(GL_POINTS);
02901           glVertex3fv(((DispCmdPoint *)cmdptr)->pos);
02902         glEnd();
02903         break;
02904 
02905       case DPOINTARRAY: 
02906         {
02907           DispCmdPointArray *pa = (DispCmdPointArray *)cmdptr;
02908           float *centers;
02909           float *colors;
02910           pa->getpointers(centers, colors);
02911 #if defined(GL_VERSION_1_1)
02912         if (!(simplegraphics || ogl_acrobat3dcapture)) {
02913           // Vertex array implementation 
02914           glDisable(GL_LIGHTING); 
02915           ogl_lightingenabled=0;
02916           glEnableClientState(GL_VERTEX_ARRAY);
02917           glEnableClientState(GL_COLOR_ARRAY);
02918           glDisableClientState(GL_NORMAL_ARRAY);
02919           glVertexPointer(3, GL_FLOAT, 12, (void *) centers);
02920           glColorPointer(3, GL_FLOAT, 12, (void *)  colors);
02921 
02922 #if defined(GL_EXT_compiled_vertex_array) 
02923           if (ext->hascompiledvertexarrayext) {
02924             GLLOCKARRAYSEXT(0, pa->numpoints);
02925           }
02926 #endif
02927 
02928           // set point size, enable blending and point antialiasing
02929           glPointSize(pa->size); 
02930           glEnable(GL_POINT_SMOOTH);
02931           glEnable(GL_BLEND);
02932           glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
02933 
02934 #if defined(VMDUSEGLSLSPHERESPRITES) && defined(GL_ARB_point_sprite)
02935           // XXX enable point sprites
02936           if (ext->hasglpointspritearb &&
02937               spherespriteshader && ogl_useglslshader) {
02938             glEnable(GL_POINT_SPRITE_ARB);
02939             glEnable(GL_VERTEX_PROGRAM_POINT_SIZE);
02940             mainshader->UseShader(0);   // switch to sphere shader
02941             spherespriteshader->UseShader(1); // switch to sphere sprite shader
02942             update_shader_uniforms(spherespriteshader, 1); // force update of shader
02943 
02944             // define sprite size in pixels
02945             GLint loc;
02946             loc = GLGETUNIFORMLOCATIONARB(spherespriteshader->ProgramObject,
02947                                           "vmdspritesize");
02948             GLfloat sz = pa->size;
02949             GLUNIFORM1FVARB(loc, 1, &sz);
02950 
02951             // Specify point sprite texture coordinate replacement mode
02952             glPushAttrib(GL_TEXTURE_BIT);
02953             glTexEnvf(GL_POINT_SPRITE_ARB, GL_COORD_REPLACE_ARB, GL_TRUE);
02954             OGLERR;
02955           }
02956 #endif
02957 
02958 #if defined(GL_ARB_point_parameters) 
02959           int dodepthscaling = 0;
02960   
02961           // enable distance based point attenuation
02962           if (ext->hasglpointparametersext  && (projection() == PERSPECTIVE)) {
02963             dodepthscaling = 1;
02964   
02965             GLfloat abc[4] = {0.0, 0.0, 1.0};
02966             GLPOINTPARAMETERFVARB(GL_POINT_DISTANCE_ATTENUATION_ARB, abc);
02967           }
02968 #endif
02969 
02970           glDrawArrays(GL_POINTS, 0, pa->numpoints);
02971 
02972 #if defined(GL_ARB_point_parameters) 
02973           // disable distance based point attenuation
02974           if (dodepthscaling) {
02975             GLfloat abc[4] = {1.0, 0.0, 0.0};
02976             GLPOINTPARAMETERFVARB(GL_POINT_DISTANCE_ATTENUATION_ARB, abc);
02977           }
02978 #endif
02979 
02980           // disable blending and point antialiasing
02981           glDisable(GL_BLEND);
02982           glDisable(GL_POINT_SMOOTH);
02983 
02984 #if defined(GL_EXT_compiled_vertex_array) 
02985           if (ext->hascompiledvertexarrayext) {
02986             GLUNLOCKARRAYSEXT();
02987           }
02988 #endif
02989 
02990 #if defined(VMDUSEGLSLSPHERESPRITES) && defined(GL_ARB_point_sprite)
02991           // XXX enable point sprites
02992           if (ext->hasglpointspritearb &&
02993               spherespriteshader && ogl_useglslshader) {
02994             glPopAttrib(); // return previous texturing state
02995             glDisable(GL_VERTEX_PROGRAM_POINT_SIZE);
02996             glDisable(GL_POINT_SPRITE_ARB);
02997             spherespriteshader->UseShader(0); // switch back to the main shader
02998             mainshader->UseShader(1);   // switch back to the main shader
02999             OGLERR;
03000           }
03001 #endif
03002 
03003           glEnableClientState(GL_NORMAL_ARRAY);
03004           glPointSize(1.0); // reset point size to default
03005         } else {
03006 #endif
03007           // Immediate mode implementation
03008           int i, ind;
03009           glBegin(GL_POINTS);
03010           ind = 0;
03011           for (i=0; i<pa->numpoints; i++) {
03012             glColor3fv(&colors[ind]);
03013             glVertex3fv(&centers[ind]); 
03014             ind += 3;
03015           }
03016           glEnd();
03017 #if defined(GL_VERSION_1_1)
03018         }
03019 #endif
03020         }
03021         break;
03022 
03023       case DLITPOINTARRAY: 
03024         {
03025         DispCmdLitPointArray *pa = (DispCmdLitPointArray *)cmdptr;
03026         float *centers;
03027         float *normals;
03028         float *colors;
03029         pa->getpointers(centers, normals, colors);
03030 #if defined(GL_VERSION_1_1)
03031         if (!(simplegraphics || ogl_acrobat3dcapture)) {
03032           // Vertex array implementation 
03033           glEnableClientState(GL_VERTEX_ARRAY);
03034           glEnableClientState(GL_COLOR_ARRAY);
03035           glEnableClientState(GL_NORMAL_ARRAY);
03036           glVertexPointer(3, GL_FLOAT, 12, (void *) centers);
03037           glNormalPointer(GL_FLOAT, 12, (void *) normals);
03038           glColorPointer(3, GL_FLOAT, 12, (void *)  colors);
03039 
03040 #if defined(GL_EXT_compiled_vertex_array) 
03041           if (ext->hascompiledvertexarrayext) {
03042             GLLOCKARRAYSEXT(0, pa->numpoints);
03043           }
03044 #endif
03045 
03046           // set point size, enable blending and point antialiasing
03047           glPointSize(pa->size); 
03048           glEnable(GL_POINT_SMOOTH);
03049 
03050 #if defined(GL_ARB_point_parameters) 
03051           int dodepthscaling = 0;
03052           // enable distance based point attenuation
03053           if (ext->hasglpointparametersext  && (projection() == PERSPECTIVE)) {
03054             dodepthscaling = 1;
03055             GLfloat abc[4] = {0.0, 0.0, 1.0};
03056             GLPOINTPARAMETERFVARB(GL_POINT_DISTANCE_ATTENUATION_ARB, abc);
03057           }
03058 #endif
03059 
03060           glDrawArrays(GL_POINTS, 0, pa->numpoints);
03061 
03062 #if defined(GL_ARB_point_parameters) 
03063           // disable distance based point attenuation
03064           if (dodepthscaling) {
03065             GLfloat abc[4] = {1.0, 0.0, 0.0};
03066             GLPOINTPARAMETERFVARB(GL_POINT_DISTANCE_ATTENUATION_ARB, abc);
03067           }
03068 #endif
03069 
03070           // disable blending and point antialiasing
03071           glDisable(GL_BLEND);
03072           glDisable(GL_POINT_SMOOTH);
03073 
03074 #if defined(GL_EXT_compiled_vertex_array) 
03075           if (ext->hascompiledvertexarrayext) {
03076             GLUNLOCKARRAYSEXT();
03077           }
03078 #endif
03079 
03080           glPointSize(1.0); // reset point size to default
03081         } else {
03082 #endif
03083           // Immediate mode implementation 
03084           int i, ind;
03085           glBegin(GL_POINTS);
03086           ind = 0;
03087           for (i=0; i<pa->numpoints; i++) {
03088             glColor3fv(&colors[ind]);
03089             glNormal3fv(&normals[ind]); 
03090             glVertex3fv(&centers[ind]); 
03091             ind += 3;
03092           }
03093           glEnd();
03094 #if defined(GL_VERSION_1_1)
03095         }
03096 #endif
03097         }
03098         break;
03099 
03100       case DLINE:
03101         // plot a line
03102         glBegin(GL_LINES);
03103           glVertex3fv(((DispCmdLine *)cmdptr)->pos1);
03104           glVertex3fv(((DispCmdLine *)cmdptr)->pos2);
03105         glEnd();
03106         break;
03107 
03108       case DLINEARRAY:
03109         {
03110           float *v = (float *)(cmdptr);
03111           int nlines = (int)v[0];
03112           v++; // move pointer forward before traversing vertex data
03113 
03114 #if defined(GL_VERSION_1_1)
03115           if (!(simplegraphics || ogl_acrobat3dcapture)) {
03116             // Vertex array implementation
03117             glInterleavedArrays(GL_V3F, 0, v);
03118 
03119 #if defined(GL_EXT_compiled_vertex_array) 
03120             if (ext->hascompiledvertexarrayext) {
03121               GLLOCKARRAYSEXT(0, 2*nlines);
03122             }
03123 #endif
03124 
03125             glDrawArrays(GL_LINES, 0, 2*nlines); 
03126 
03127 #if defined(GL_EXT_compiled_vertex_array) 
03128             if (ext->hascompiledvertexarrayext) {
03129               GLUNLOCKARRAYSEXT();
03130             }
03131 #endif
03132           } else {
03133 #endif
03134             // Immediate mode implementation
03135             glBegin(GL_LINES);
03136             for (int i=0; i<nlines; i++) {
03137               glVertex3fv(v);
03138               glVertex3fv(v+3);
03139               v += 6;
03140             }
03141             glEnd();
03142 #if defined(GL_VERSION_1_1)
03143           }
03144 #endif
03145         }
03146         break;    
03147 
03148       case DPOLYLINEARRAY:
03149         {
03150           float *v = (float *)(cmdptr);
03151           int nverts = (int)v[0];
03152           v++; // move pointer forward before traversing vertex data
03153 
03154 #if defined(GL_VERSION_1_1)
03155           if (!(simplegraphics || ogl_acrobat3dcapture)) {
03156             // Vertex array implementation
03157             glInterleavedArrays(GL_V3F, 0, v);
03158 
03159 #if defined(GL_EXT_compiled_vertex_array) 
03160             if (ext->hascompiledvertexarrayext) {
03161               GLLOCKARRAYSEXT(0, nverts);
03162             }
03163 #endif
03164 
03165             glDrawArrays(GL_LINE_STRIP, 0, nverts); 
03166 
03167 #if defined(GL_EXT_compiled_vertex_array) 
03168             if (ext->hascompiledvertexarrayext) {
03169               GLUNLOCKARRAYSEXT();
03170             }
03171 #endif
03172           } else {
03173 #endif
03174             // Immediate mode implementation
03175             glBegin(GL_LINE_STRIP);
03176             for (int i=0; i<nverts; i++) {
03177               glVertex3fv(v);
03178               v += 3;
03179             }
03180             glEnd();
03181 #if defined(GL_VERSION_1_1)
03182           }
03183 #endif
03184         }
03185         break;    
03186 
03187       case DSPHERE: 
03188         {
03189         float *p = (float *)cmdptr;
03190         glPushMatrix();
03191         glTranslatef(p[0], p[1], p[2]); 
03192         glScalef(p[3], p[3], p[3]);
03193         glCallList(SphereList);
03194         glPopMatrix();
03195         }
03196         break;
03197 
03198       case DSPHEREARRAY: 
03199         {
03200         DispCmdSphereArray *sa = (DispCmdSphereArray *)cmdptr;
03201         int i, ind;
03202         float * centers;
03203         float * radii;
03204         float * colors;
03205         sa->getpointers(centers, radii, colors);
03206 
03207 #if defined(VMDUSEGLSLSPHERES) 
03208         // Render the sphere using programmable shading via ray-casting
03209         if (sphereshader && ogl_useglslshader) {
03210           // coordinates of unit bounding box
03211           GLfloat v0[] = {-1.0, -1.0, -1.0}; 
03212           GLfloat v1[] = { 1.0, -1.0, -1.0}; 
03213           GLfloat v2[] = {-1.0,  1.0, -1.0}; 
03214           GLfloat v3[] = { 1.0,  1.0, -1.0}; 
03215           GLfloat v4[] = {-1.0, -1.0,  1.0}; 
03216           GLfloat v5[] = { 1.0, -1.0,  1.0}; 
03217           GLfloat v6[] = {-1.0,  1.0,  1.0}; 
03218           GLfloat v7[] = { 1.0,  1.0,  1.0}; 
03219       
03220           mainshader->UseShader(0);   // switch to sphere shader
03221           sphereshader->UseShader(1); // switch to sphere shader
03222           update_shader_uniforms(sphereshader, 1); // force update of shader
03223 
03224           // Update projection parameters for OpenGL shader
03225           GLfloat projparms[4];
03226           projparms[0] = nearClip;
03227           projparms[1] = farClip; 
03228           projparms[2] = 0.5f * (farClip + nearClip);
03229           projparms[3] = 1.0f / (farClip - nearClip);
03230           GLint projloc = GLGETUNIFORMLOCATIONARB(sphereshader->ProgramObject, "vmdprojparms");
03231           GLUNIFORM4FVARB(projloc, 1, projparms);
03232           OGLERR;
03233 
03234           ind = 0;
03235           for (i=0; i<sa->numspheres; i++) {
03236             glPushMatrix();
03237             glTranslatef(centers[ind], centers[ind + 1], centers[ind + 2]); 
03238             glScalef(radii[i], radii[i], radii[i]);
03239             glColor3fv(&colors[ind]);
03240 
03241             // Draw the bounding box containing the sphere, gauranteeing 
03242             // that it will be correctly rendered regardless of the 
03243             // perspective projection used, viewing direction, etc.
03244             // If enough is known about the projection being used, this
03245             // could be done with simple billboard polygons, or perhaps even
03246             // a large OpenGL point primitive instead of a whole cube
03247             glBegin(GL_QUADS);
03248               glVertex3fv((GLfloat *) v0); /* -Z face */
03249               glVertex3fv((GLfloat *) v1);
03250               glVertex3fv((GLfloat *) v3);
03251               glVertex3fv((GLfloat *) v2);
03252 
03253               glVertex3fv((GLfloat *) v4); /* +Z face */
03254               glVertex3fv((GLfloat *) v5);
03255               glVertex3fv((GLfloat *) v7);
03256               glVertex3fv((GLfloat *) v6);
03257 
03258               glVertex3fv((GLfloat *) v0); /* -Y face */
03259               glVertex3fv((GLfloat *) v1);
03260               glVertex3fv((GLfloat *) v5);
03261               glVertex3fv((GLfloat *) v4);
03262 
03263               glVertex3fv((GLfloat *) v2); /* +Y face */
03264               glVertex3fv((GLfloat *) v3);
03265               glVertex3fv((GLfloat *) v7);
03266               glVertex3fv((GLfloat *) v6);
03267 
03268               glVertex3fv((GLfloat *) v0); /* -X face */
03269               glVertex3fv((GLfloat *) v2);
03270               glVertex3fv((GLfloat *) v6);
03271               glVertex3fv((GLfloat *) v4);
03272 
03273               glVertex3fv((GLfloat *) v1); /* +X face */
03274               glVertex3fv((GLfloat *) v3);
03275               glVertex3fv((GLfloat *) v7);
03276               glVertex3fv((GLfloat *) v5);
03277             glEnd();
03278             glPopMatrix();
03279             ind += 3; // next sphere
03280           }
03281 
03282           sphereshader->UseShader(0); // switch back to the main shader
03283           mainshader->UseShader(1);   // switch back to the main shader
03284           OGLERR;
03285         } else {
03286 #endif
03287           // OpenGL display listed sphere rendering implementation
03288           set_sphere_res(sa->sphereres); // set the current sphere resolution
03289 
03290           // use single-sided lighting when drawing spheres for 
03291           // peak rendering speed.
03292           glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_FALSE);
03293           ind = 0;
03294           for (i=0; i<sa->numspheres; i++) {
03295             glPushMatrix();
03296             glTranslatef(centers[ind], centers[ind + 1], centers[ind + 2]); 
03297             glScalef(radii[i], radii[i], radii[i]);
03298             glColor3fv(&colors[ind]);
03299             glCallList(SphereList);
03300             glPopMatrix();
03301             ind += 3; // next sphere
03302           }
03303           glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_TRUE);
03304 #if defined(VMDUSEGLSLSPHERES)
03305         }
03306 #endif
03307 
03308         }
03309         break;
03310 
03311       case DCUBEARRAY: 
03312         {
03313           DispCmdLatticeCubeArray *ca = (DispCmdLatticeCubeArray *)cmdptr;
03314           int i, ind;
03315           float * centers;
03316           float * radii;
03317           float * colors;
03318           ca->getpointers(centers, radii, colors);
03319 
03320           // Render the cube 
03321           // coordinates of unit cube
03322           GLfloat v0[] = {-1.0, -1.0, -1.0}; 
03323           GLfloat v1[] = { 1.0, -1.0, -1.0}; 
03324           GLfloat v2[] = {-1.0,  1.0, -1.0}; 
03325           GLfloat v3[] = { 1.0,  1.0, -1.0}; 
03326           GLfloat v4[] = {-1.0, -1.0,  1.0}; 
03327           GLfloat v5[] = { 1.0, -1.0,  1.0}; 
03328           GLfloat v6[] = {-1.0,  1.0,  1.0}; 
03329           GLfloat v7[] = { 1.0,  1.0,  1.0}; 
03330       
03331           ind = 0;
03332           for (i=0; i<ca->numcubes; i++) {
03333             glPushMatrix();
03334             glTranslatef(centers[ind], centers[ind + 1], centers[ind + 2]); 
03335             glScalef(radii[i], radii[i], radii[i]);
03336             glColor3fv(&colors[ind]);
03337 
03338             // Draw the unit cube
03339             glBegin(GL_QUADS);
03340               glNormal3f(0.0f, 0.0f, 1.0f);
03341               glVertex3fv((GLfloat *) v0); /* -Z face */
03342               glVertex3fv((GLfloat *) v1);
03343               glVertex3fv((GLfloat *) v3);
03344               glVertex3fv((GLfloat *) v2);
03345 
03346               glNormal3f(0.0f, 0.0f, 1.0f);
03347               glVertex3fv((GLfloat *) v4); /* +Z face */
03348               glVertex3fv((GLfloat *) v5);
03349               glVertex3fv((GLfloat *) v7);
03350               glVertex3fv((GLfloat *) v6);
03351 
03352               glNormal3f(0.0f, -1.0f, 0.0f);
03353               glVertex3fv((GLfloat *) v0); /* -Y face */
03354               glVertex3fv((GLfloat *) v1);
03355               glVertex3fv((GLfloat *) v5);
03356               glVertex3fv((GLfloat *) v4);
03357 
03358               glNormal3f(0.0f, -1.0f, 0.0f);
03359               glVertex3fv((GLfloat *) v2); /* +Y face */
03360               glVertex3fv((GLfloat *) v3);
03361               glVertex3fv((GLfloat *) v7);
03362               glVertex3fv((GLfloat *) v6);
03363 
03364               glNormal3f(1.0f, 0.0f, 0.0f);
03365               glVertex3fv((GLfloat *) v0); /* -X face */
03366               glVertex3fv((GLfloat *) v2);
03367               glVertex3fv((GLfloat *) v6);
03368               glVertex3fv((GLfloat *) v4);
03369 
03370               glNormal3f(1.0f, 0.0f, 0.0f);
03371               glVertex3fv((GLfloat *) v1); /* +X face */
03372               glVertex3fv((GLfloat *) v3);
03373               glVertex3fv((GLfloat *) v7);
03374               glVertex3fv((GLfloat *) v5);
03375             glEnd();
03376             glPopMatrix();
03377             ind += 3; // next sphere
03378           }
03379           OGLERR;
03380         }
03381         break;
03382 
03383       case DTRIANGLE: 
03384         {
03385         DispCmdTriangle *cmd = (DispCmdTriangle *)cmdptr;
03386         glBegin(GL_TRIANGLES);
03387           glNormal3fv(cmd->norm1);
03388           glVertex3fv(cmd->pos1);
03389           glNormal3fv(cmd->norm2);
03390           glVertex3fv(cmd->pos2);
03391           glNormal3fv(cmd->norm3);
03392           glVertex3fv(cmd->pos3);
03393         glEnd();
03394         }
03395         break;
03396 
03397       case DSQUARE:
03398         // draw a square, given the four points
03399         {
03400         DispCmdSquare *cmd = (DispCmdSquare *)cmdptr;
03401         glBegin(GL_QUADS);
03402           glNormal3fv((GLfloat *) cmd->norml);
03403           glVertex3fv((GLfloat *) cmd->pos1);
03404           glVertex3fv((GLfloat *) cmd->pos2);
03405           glVertex3fv((GLfloat *) cmd->pos3);
03406           glVertex3fv((GLfloat *) cmd->pos4);
03407         glEnd();
03408         }
03409         break;
03410 
03411 #if 0
03412       case DSTRIPETEX:
03413         if (ext->hastex3d) {
03414 #if defined(GL_VERSION_1_2)
03415 #define STRIPEWIDTH 32
03416           GLubyte stripeImage[4 * STRIPEWIDTH];
03417           GLuint texName = 0;
03418           // glGenTextures(1, &texName);
03419           int i;
03420           for (i=0; i<STRIPEWIDTH; i++) {
03421             stripeImage[4*i    ] = (GLubyte) ((i>4) ? 255 : 0); // R
03422             stripeImage[4*i + 1] = (GLubyte) ((i>4) ? 255 : 0); // G
03423             stripeImage[4*i + 2] = (GLubyte) ((i>4) ? 255 : 0); // B
03424             stripeImage[4*i + 3] = (GLubyte) 255;               // W
03425           }
03426 
03427           glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
03428           glBindTexture(GL_TEXTURE_1D, texName);
03429           glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_WRAP_S, GL_REPEAT);
03430           glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_WRAP_T, GL_REPEAT);
03431           glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_WRAP_R, GL_REPEAT);
03432           glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
03433           glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
03434           glTexImage1D(GL_TEXTURE_1D, 0, GL_RGBA, STRIPEWIDTH, 
03435                           0, GL_RGBA, GL_UNSIGNED_BYTE, stripeImage);
03436 
03437           // XXX should use GL_MODULATE, but requires all polygons to be
03438           //     drawn "white", in order for shading to make it through the
03439           //     texturing process.  GL_REPLACE works well for situations
03440           //     where we want coloring to come entirely from texture.
03441           glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
03442           GLfloat xplaneeq[4] = {0.5, 0.0, 0.0, 0.0};
03443           glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
03444           glTexGenfv(GL_S, GL_EYE_PLANE, xplaneeq);
03445           glEnable(GL_TEXTURE_GEN_S);
03446           glEnable(GL_TEXTURE_1D);
03447 #endif
03448         }
03449         break;
03450 
03451       case DSTRIPETEXOFF:
03452         if (ext->hastex3d) {
03453 #if defined(GL_VERSION_1_2)
03454           glDisable(GL_TEXTURE_GEN_S);
03455           glDisable(GL_TEXTURE_1D);
03456 #endif
03457         }
03458         break;
03459 #endif
03460 
03461       case DVOLUMETEXTURE:
03462         if (ext->hastex3d)
03463 #if defined(GL_VERSION_1_2)
03464         {
03465   
03466 #if defined(GL_GENERATE_MIPMAP_HINT)
03467           // set MIP map generation hint for high quality
03468           glHint(GL_GENERATE_MIPMAP_HINT, GL_NICEST);
03469 #endif
03470           glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
03471 
03472           DispCmdVolumeTexture *cmd = (DispCmdVolumeTexture *)cmdptr;
03473           require_volume_texture(cmd->ID, 
03474               cmd->xsize, cmd->ysize, cmd->zsize, 
03475               cmd->texmap);
03476 
03477           GLfloat xplaneeq[4]; 
03478           GLfloat yplaneeq[4]; 
03479           GLfloat zplaneeq[4]; 
03480           int i;
03481 
03482           glEnable(GL_TEXTURE_3D);
03483           glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
03484 
03485 #if defined(VMDUSEOPENGLSHADER)
03486           // Update active GLSL texturing mode
03487           if (mainshader && ogl_useglslshader) {
03488             if (!ogl_lightingenabled)
03489               mainshader->UseShader(1); // enable shader so state updates 
03490             ogl_glsltexturemode = 1;
03491             GLint vmdtexturemode = 1;  // enable 3-D texturing->MODULATE
03492             GLint loc = GLGETUNIFORMLOCATIONARB(mainshader->ProgramObject, "vmdtexturemode");
03493             GLUNIFORM1IARB(loc, vmdtexturemode);
03494       
03495             // Set active texture map index
03496             loc = GLGETUNIFORMLOCATIONARB(mainshader->ProgramObject, "vmdtex0");
03497             GLUNIFORM1IARB(loc, 0); // using texture unit 0
03498             if (!ogl_lightingenabled)
03499               mainshader->UseShader(0); // disable shader after state updates
03500           }
03501 #endif
03502 
03503           // automatically generate texture coordinates by translating from
03504           // model coordinate space to volume coordinates.  These aren't
03505           // going to be used by volume slices, but the performance hit
03506           // is expected to be insignificant.
03507           for (i=0; i<3; i++) {
03508             xplaneeq[i] = cmd->v1[i];
03509             yplaneeq[i] = cmd->v2[i];
03510             zplaneeq[i] = cmd->v3[i];
03511           }
03512           xplaneeq[3] = cmd->v0[0];
03513           yplaneeq[3] = cmd->v0[1];
03514           zplaneeq[3] = cmd->v0[2];
03515 
03516           glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR); 
03517           glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR); 
03518           glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR); 
03519           glTexGenfv(GL_S, GL_EYE_PLANE, xplaneeq);
03520           glTexGenfv(GL_T, GL_EYE_PLANE, yplaneeq);
03521           glTexGenfv(GL_R, GL_EYE_PLANE, zplaneeq);
03522           glEnable(GL_TEXTURE_GEN_S);
03523           glEnable(GL_TEXTURE_GEN_T);
03524           glEnable(GL_TEXTURE_GEN_R);
03525 #endif
03526         }
03527         break;
03528 
03529       case DVOLTEXON:
03530         if (ext->hastex3d) {
03531 #if defined(GL_VERSION_1_2)
03532           glEnable(GL_TEXTURE_3D);     // enable volume texturing
03533 #if defined(VMDUSEOPENGLSHADER)
03534           // Update active GLSL texturing mode
03535           if (mainshader && ogl_useglslshader) {
03536             if (!ogl_lightingenabled)
03537               mainshader->UseShader(1); // enable shader so state updates 
03538             ogl_glsltexturemode = 1;
03539             GLint vmdtexturemode = 1;  // enable 3-D texturing->MODULATE
03540             GLint loc = GLGETUNIFORMLOCATIONARB(mainshader->ProgramObject, "vmdtexturemode");
03541             GLUNIFORM1IARB(loc, vmdtexturemode);
03542             if (!ogl_lightingenabled)
03543               mainshader->UseShader(0); // disable shader after state updates
03544           }
03545 #endif
03546           glEnable(GL_TEXTURE_GEN_S);  // enable automatic texture 
03547           glEnable(GL_TEXTURE_GEN_T);  //   coordinate generation
03548           glEnable(GL_TEXTURE_GEN_R);
03549 #endif
03550         }
03551         break;
03552 
03553       case DVOLTEXOFF:
03554         if (ext->hastex3d) {
03555 #if defined(GL_VERSION_1_2)
03556           glDisable(GL_TEXTURE_3D);     // disable volume texturing
03557 #if defined(VMDUSEOPENGLSHADER)
03558           // Update active GLSL texturing mode
03559           if (mainshader && ogl_useglslshader) {
03560             if (!ogl_lightingenabled)
03561               mainshader->UseShader(1); // enable shader so state updates 
03562             ogl_glsltexturemode = 0;
03563             GLint vmdtexturemode = 0;  // disable 3-D texturing
03564             GLint loc = GLGETUNIFORMLOCATIONARB(mainshader->ProgramObject, "vmdtexturemode");
03565             GLUNIFORM1IARB(loc, vmdtexturemode);
03566             if (!ogl_lightingenabled)
03567               mainshader->UseShader(0); // disable shader after state updates
03568           }
03569 #endif
03570 
03571           glDisable(GL_TEXTURE_GEN_S);  // disable automatic texture 
03572           glDisable(GL_TEXTURE_GEN_T);  //   coordinate generation
03573           glDisable(GL_TEXTURE_GEN_R);
03574 #endif
03575         }
03576         break;
03577 
03578 
03579       case DVOLSLICE:
03580         if (ext->hastex3d) {
03581           DispCmdVolSlice *cmd = (DispCmdVolSlice *)cmdptr;
03582 #if defined(GL_VERSION_1_2)
03583 
03584           // DVOLUMETEXTURE does most of the work for us, but we override
03585           // a few of the texenv settings
03586           glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
03587 
03588           // enable or disable texture interpolation and filtering
03589           switch (cmd->texmode) {
03590             case 2:
03591               glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
03592               glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
03593               glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
03594               break;
03595 
03596             case 1:
03597               glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_DONT_CARE);
03598               glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
03599               glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
03600               break;
03601      
03602             case 0: 
03603             default:
03604               glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_FASTEST);
03605               glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
03606               glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
03607               break;
03608           }
03609       
03610           // use the texture edge colors rather border color when wrapping
03611           glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
03612           glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
03613           glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
03614 
03615 #if defined(VMDUSEOPENGLSHADER)
03616           // Update active GLSL texturing mode
03617           if (mainshader && ogl_useglslshader) {
03618             ogl_glsltexturemode = 2;
03619             GLint vmdtexturemode = 2;  // enable 3-D texturing->REPLACE
03620             GLint loc = GLGETUNIFORMLOCATIONARB(mainshader->ProgramObject, "vmdtexturemode");
03621             GLUNIFORM1IARB(loc, vmdtexturemode);
03622           }
03623 #endif
03624           glBegin(GL_QUADS);        
03625           for (int i=0; i<4; i++) {
03626             glNormal3fv(cmd->normal);
03627             glVertex3fv(cmd->v + 3*i);
03628           }
03629           glEnd();        
03630 #endif // GL_VERSION_1_2
03631         } 
03632         break;
03633 
03634       case DTRIMESH_C3F_N3F_V3F: 
03635         { 
03636         // draw a triangle mesh
03637         DispCmdTriMesh *cmd = (DispCmdTriMesh *) cmdptr;
03638         float *colors=NULL, *normals=NULL, *vertices=NULL;
03639 
03640         if (cmd->pervertexcolors)
03641           cmd->getpointers(colors, normals, vertices);
03642         else
03643           cmd->getpointers(normals, vertices);
03644 
03645 #if 1
03646 #if defined(GL_VERSION_1_1)
03647         if (!(simplegraphics || ogl_acrobat3dcapture)) {
03648           // Vertex array implementation
03649           if (cmd->pervertexcolors)
03650             glEnableClientState(GL_COLOR_ARRAY);
03651           else
03652             glDisableClientState(GL_COLOR_ARRAY);
03653           glEnableClientState(GL_NORMAL_ARRAY);
03654           glEnableClientState(GL_VERTEX_ARRAY);
03655 
03656           if (cmd->pervertexcolors)
03657             glColorPointer(3, GL_FLOAT, 0, (void *) colors);
03658           glNormalPointer(GL_FLOAT, 0, (void *) normals);
03659           glVertexPointer(3, GL_FLOAT, 0, (void *) vertices);
03660 
03661 #if defined(GL_EXT_compiled_vertex_array)
03662           if (ext->hascompiledvertexarrayext) {
03663             GLLOCKARRAYSEXT(0, cmd->numverts);
03664           }
03665 #endif
03666 
03667           glDrawArrays(GL_TRIANGLES, 0, cmd->numverts);
03668 
03669 #if defined(GL_EXT_compiled_vertex_array)
03670           if (ext->hascompiledvertexarrayext) {
03671             GLUNLOCKARRAYSEXT();
03672           }
03673 #endif
03674         } else {
03675 #endif
03676           // Immediate mode implementation
03677           int i, ind;
03678           glBegin(GL_TRIANGLES);
03679           ind = 0;
03680           if (cmd->pervertexcolors) {
03681             for (i=0; i<cmd->numverts; i++) {
03682               glColor3fv(&colors[ind]);
03683               glNormal3fv(&normals[ind]);
03684               glVertex3fv(&vertices[ind]);
03685               ind += 3;
03686             }
03687           } else {
03688             for (i=0; i<cmd->numverts; i++) {
03689               glNormal3fv(&normals[ind]);
03690               glVertex3fv(&vertices[ind]);
03691               ind += 3;
03692             }
03693           }
03694 
03695           glEnd();
03696 #if defined(GL_VERSION_1_1)
03697         }
03698 #endif
03699 
03700 #endif
03701         }
03702         break;
03703 
03704       case DTRIMESH_C4F_N3F_V3F: 
03705         {
03706         // draw a triangle mesh
03707         DispCmdTriMesh *cmd = (DispCmdTriMesh *) cmdptr;
03708         int ind = cmd->numfacets * 3;
03709         float *cnv;
03710         int *f;
03711         cmd->getpointers(cnv, f);
03712 
03713 #if defined(GL_VERSION_1_1)
03714         // Vertex array implementation
03715         if (!(simplegraphics || ogl_acrobat3dcapture)) {
03716           // If OpenGL 1.1, then use vertex arrays 
03717           glInterleavedArrays(GL_C4F_N3F_V3F, 0, cnv);
03718 
03719 #if defined(GL_EXT_compiled_vertex_array) 
03720           if (ext->hascompiledvertexarrayext) {
03721             GLLOCKARRAYSEXT(0, cmd->numverts);
03722           }
03723 #endif
03724 
03725           glDrawElements(GL_TRIANGLES, ind, GL_UNSIGNED_INT, f);
03726 
03727 #if defined(GL_EXT_compiled_vertex_array) 
03728           if (ext->hascompiledvertexarrayext) {
03729             GLUNLOCKARRAYSEXT();
03730           }
03731 #endif
03732         } else {
03733 #endif
03734 
03735           // simple graphics mode, but not Acrobat3D capture mode
03736           if (!ogl_acrobat3dcapture) {
03737             int i, ind2;
03738             glBegin(GL_TRIANGLES);
03739             for (i=0; i<ind; i++) {
03740               ind2 = f[i] * 10;
03741                glColor3fv(cnv + ind2    );
03742               glNormal3fv(cnv + ind2 + 4);
03743               glVertex3fv(cnv + ind2 + 7);
03744             }
03745             glEnd();
03746           } else { 
03747             // Version 7.0.9 of Acrobat3D can't capture multicolor
03748             // triangles, so we revert to averaged-single-color
03749             // triangles until they fix this capture bug.
03750             int i;
03751             for (i=0; i<cmd->numfacets; i++) {
03752               int ind = i * 3;
03753               float tmp[3], tmp2[3];
03754 
03755               int v0 = f[ind    ] * 10;
03756               int v1 = f[ind + 1] * 10;
03757               int v2 = f[ind + 2] * 10;
03758 
03759               vec_add(tmp, cnv + v0, cnv + v1);
03760               vec_add(tmp2, tmp, cnv + v2);
03761               vec_scale(tmp, 0.3333333f, tmp2);
03762               glBegin(GL_TRIANGLES);
03763               glColor3fv(tmp);
03764               glNormal3fv(cnv + v0 + 4);
03765               glVertex3fv(cnv + v0 + 7);
03766               glNormal3fv(cnv + v1 + 4);
03767               glVertex3fv(cnv + v1 + 7);
03768               glNormal3fv(cnv + v2 + 4);
03769               glVertex3fv(cnv + v2 + 7);
03770               glEnd();
03771             }
03772           }
03773 
03774 #if defined(GL_VERSION_1_1)
03775         }
03776 #endif
03777         }
03778         break;
03779 
03780 
03781       case DTRIMESH_C4U_N3F_V3F: 
03782         { 
03783         // draw a triangle mesh
03784         DispCmdTriMesh *cmd = (DispCmdTriMesh *) cmdptr;
03785         unsigned char *colors=NULL;
03786         float *normals=NULL, *vertices=NULL;
03787 
03788         if (cmd->pervertexcolors)
03789           cmd->getpointers(colors, normals, vertices);
03790         else
03791           cmd->getpointers(normals, vertices);
03792 
03793 #if 1
03794 #if defined(GL_VERSION_1_1)
03795         if (!(simplegraphics || ogl_acrobat3dcapture)) {
03796           // Vertex array implementation
03797           if (cmd->pervertexcolors)
03798             glEnableClientState(GL_COLOR_ARRAY);
03799           else
03800             glDisableClientState(GL_COLOR_ARRAY);
03801           glEnableClientState(GL_NORMAL_ARRAY);
03802           glEnableClientState(GL_VERTEX_ARRAY);
03803 
03804           if (cmd->pervertexcolors)
03805             glColorPointer(4, GL_UNSIGNED_BYTE, 0, (void *) colors);
03806           glNormalPointer(GL_FLOAT, 0, (void *) normals);
03807           glVertexPointer(3, GL_FLOAT, 0, (void *) vertices);
03808 
03809 #if defined(GL_EXT_compiled_vertex_array)
03810           if (ext->hascompiledvertexarrayext) {
03811             GLLOCKARRAYSEXT(0, cmd->numverts);
03812           }
03813 #endif
03814 
03815           glDrawArrays(GL_TRIANGLES, 0, cmd->numverts);
03816 
03817 #if defined(GL_EXT_compiled_vertex_array)
03818           if (ext->hascompiledvertexarrayext) {
03819             GLUNLOCKARRAYSEXT();
03820           }
03821 #endif
03822         } else {
03823 #endif
03824           // Immediate mode implementation
03825           int i, ind;
03826           glBegin(GL_TRIANGLES);
03827           ind = 0;
03828           if (cmd->pervertexcolors) {
03829             for (i=0; i<cmd->numverts; i++) {
03830               glColor3ubv(&colors[ind]);
03831               glNormal3fv(&normals[ind]);
03832               glVertex3fv(&vertices[ind]);
03833               ind += 3;
03834             }
03835           } else {
03836             for (i=0; i<cmd->numverts; i++) {
03837               glNormal3fv(&normals[ind]);
03838               glVertex3fv(&vertices[ind]);
03839               ind += 3;
03840             }
03841           }
03842 
03843           glEnd();
03844 #if defined(GL_VERSION_1_1)
03845         }
03846 #endif
03847 
03848 #endif
03849         }
03850         break;
03851 
03852 
03853       case DTRIMESH_C4U_N3B_V3F: 
03854         { 
03855         // draw a triangle mesh
03856         DispCmdTriMesh *cmd = (DispCmdTriMesh *) cmdptr;
03857         unsigned char *colors=NULL;
03858         char *normals=NULL;
03859         float *vertices=NULL;
03860 
03861         if (cmd->pervertexcolors)
03862           cmd->getpointers(colors, normals, vertices);
03863         else
03864           cmd->getpointers(normals, vertices);
03865 
03866 #if 1
03867 #if defined(GL_VERSION_1_1)
03868         if (!(simplegraphics || ogl_acrobat3dcapture)) {
03869           // Vertex array implementation
03870           if (cmd->pervertexcolors)
03871             glEnableClientState(GL_COLOR_ARRAY);
03872           else
03873             glDisableClientState(GL_COLOR_ARRAY);
03874           glEnableClientState(GL_NORMAL_ARRAY);
03875           glEnableClientState(GL_VERTEX_ARRAY);
03876 
03877           if (cmd->pervertexcolors)
03878             glColorPointer(4, GL_UNSIGNED_BYTE, 0, (void *) colors);
03879           glNormalPointer(GL_BYTE, 0, (void *) normals);
03880           glVertexPointer(3, GL_FLOAT, 0, (void *) vertices);
03881 
03882 #if defined(GL_EXT_compiled_vertex_array)
03883           if (ext->hascompiledvertexarrayext) {
03884             GLLOCKARRAYSEXT(0, cmd->numverts);
03885           }
03886 #endif
03887 
03888           glDrawArrays(GL_TRIANGLES, 0, cmd->numverts);
03889 
03890 #if defined(GL_EXT_compiled_vertex_array)
03891           if (ext->hascompiledvertexarrayext) {
03892             GLUNLOCKARRAYSEXT();
03893           }
03894 #endif
03895         } else {
03896 #endif
03897           // Immediate mode implementation
03898           int i, ind;
03899           glBegin(GL_TRIANGLES);
03900           ind = 0;
03901           if (cmd->pervertexcolors) {
03902             for (i=0; i<cmd->numverts; i++) {
03903               glColor3ubv(&colors[ind]);
03904               glNormal3bv((GLbyte *) &normals[ind]);
03905               glVertex3fv(&vertices[ind]);
03906               ind += 3;
03907             }
03908           } else {
03909             for (i=0; i<cmd->numverts; i++) {
03910               glNormal3bv((GLbyte *) &normals[ind]);
03911               glVertex3fv(&vertices[ind]);
03912               ind += 3;
03913             }
03914           }
03915 
03916           glEnd();
03917 #if defined(GL_VERSION_1_1)
03918         }
03919 #endif
03920 
03921 #endif
03922         }
03923         break;
03924 
03925         
03926       case DTRISTRIP: 
03927         {
03928         // draw triangle strips
03929         DispCmdTriStrips *cmd = (DispCmdTriStrips *) cmdptr;
03930         int numstrips = cmd->numstrips;
03931         int strip;
03932 
03933         float *cnv;
03934         int *f;
03935         int *vertsperstrip;
03936 
03937         cmd->getpointers(cnv, f, vertsperstrip);
03938 
03939         // use single-sided lighting when drawing possible, for
03940         // peak rendering speed.
03941         if (!cmd->doublesided) {
03942           glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_FALSE);
03943         }
03944 
03945 #if defined(GL_VERSION_1_1)
03946         if (!(simplegraphics || ogl_acrobat3dcapture)) {
03947           // If OpenGL 1.1, then use vertex arrays
03948           glInterleavedArrays(GL_C4F_N3F_V3F, 0, cnv);
03949 
03950 #if defined(GL_EXT_compiled_vertex_array) 
03951           if (ext->hascompiledvertexarrayext) {
03952             GLLOCKARRAYSEXT(0, cmd->numverts);
03953           }
03954 #endif
03955 
03956 #if defined(GL_EXT_multi_draw_arrays)
03957           // Try the Sun/ARB MultiDrawElements() extensions first.
03958           if (ext->hasmultidrawext) {
03959             int **indices = new int *[cmd->numstrips];
03960 
03961             // build array of facet list pointers to allow the renderer to
03962             // send everything in a single command/DMA when possible
03963             int qv=0;
03964             for (int i=0; i<numstrips; i++) {
03965               indices[i] = (int *) ((char *)f + qv * sizeof(int));
03966               qv += vertsperstrip[i]; // incr vertex index, next strip
03967             }
03968 
03969             GLMULTIDRAWELEMENTSEXT(GL_TRIANGLE_STRIP, 
03970                                    (GLsizei *) vertsperstrip, 
03971                                    GL_UNSIGNED_INT, 
03972                                    (const GLvoid **) indices, 
03973                                    numstrips);
03974 
03975             delete [] indices;
03976           }
03977           else  // if not MDE, then fall back to other techniques
03978 #endif
03979           // Use the regular OpenGL 1.1 vertex array APIs, loop over all strips
03980           {
03981             int qv=0;
03982             for (strip=0; strip < numstrips; strip++) {
03983               glDrawElements(GL_TRIANGLE_STRIP, vertsperstrip[strip],
03984                              GL_UNSIGNED_INT, (int *) ((char *) f + qv * sizeof(int)));
03985               qv += vertsperstrip[strip];
03986             }
03987           }
03988 
03989 #if defined(GL_EXT_compiled_vertex_array) 
03990           if (ext->hascompiledvertexarrayext) {
03991             GLUNLOCKARRAYSEXT();
03992           }
03993 #endif
03994         } else {
03995 #endif
03996           // simple graphics mode, but not Acrobat3D capture mode
03997           if (!ogl_acrobat3dcapture) {
03998             // No OpenGL 1.1? ouch, then we have to do this the slow way
03999             int t, ind;
04000             int v = 0; // current vertex index, initially 0
04001             // loop over all of the triangle strips
04002             for (strip=0; strip < numstrips; strip++) {         
04003               glBegin(GL_TRIANGLE_STRIP);
04004               // render all of the triangles in this strip
04005               for (t = 0; t < vertsperstrip[strip]; t++) {
04006                 ind = f[v] * 10;
04007                  glColor3fv(cnv + ind    );
04008                 glNormal3fv(cnv + ind + 4);
04009                 glVertex3fv(cnv + ind + 7);
04010                 v++; // increment vertex index, for the next triangle
04011               }
04012               glEnd();
04013             }
04014           } else {
04015             // Acrobat3D capture mode works around several bugs in the
04016             // capture utility provided with version 7.x.  Their capture
04017             // feature can't catch triangle strips, so we have to render
04018             // each of the triangles individually.
04019 
04020             // render triangle strips one triangle at a time
04021             // triangle winding order is:
04022             //   v0, v1, v2, then v2, v1, v3, then v2, v3, v4, etc.
04023             int strip, t, v = 0;
04024             int stripaddr[2][3] = { {0, 1, 2}, {1, 0, 2} };
04025 
04026             // loop over all of the triangle strips
04027             for (strip=0; strip < numstrips; strip++) {
04028               // loop over all triangles in this triangle strip
04029               glBegin(GL_TRIANGLES);
04030 
04031               for (t = 0; t < (vertsperstrip[strip] - 2); t++) {
04032                 // render one triangle, using lookup table to fix winding order
04033                 int v0 = f[v + (stripaddr[t & 0x01][0])] * 10;
04034                 int v1 = f[v + (stripaddr[t & 0x01][1])] * 10;
04035                 int v2 = f[v + (stripaddr[t & 0x01][2])] * 10;
04036 
04037 #if 1
04038                 // Version 7.0.9 of Acrobat3D can't capture multicolor
04039                 // triangles, so we revert to averaged-single-color
04040                 // triangles until they fix this capture bug.
04041                 float tmp[3], tmp2[3];
04042                 vec_add(tmp, cnv + v0, cnv + v1); 
04043                 vec_add(tmp2, tmp, cnv + v2); 
04044                 vec_scale(tmp, 0.3333333f, tmp2);
04045                 glColor3fv(tmp);
04046                 glNormal3fv(cnv + v0 + 4);
04047                 glVertex3fv(cnv + v0 + 7);
04048                 glNormal3fv(cnv + v1 + 4);
04049                 glVertex3fv(cnv + v1 + 7);
04050                 glNormal3fv(cnv + v2 + 4);
04051                 glVertex3fv(cnv + v2 + 7);
04052 #else
04053                  glColor3fv(cnv + v0    );
04054                 glNormal3fv(cnv + v0 + 4);
04055                 glVertex3fv(cnv + v0 + 7);
04056                  glColor3fv(cnv + v1    );
04057                 glNormal3fv(cnv + v1 + 4);
04058                 glVertex3fv(cnv + v1 + 7);
04059                  glColor3fv(cnv + v2    );
04060                 glNormal3fv(cnv + v2 + 4);
04061                 glVertex3fv(cnv + v2 + 7);
04062 #endif
04063 
04064                 v++; // move on to next vertex
04065               }
04066               glEnd();
04067               v+=2; // last two vertices are already used by last triangle
04068             }
04069           }
04070 
04071 #if defined(GL_VERSION_1_1)
04072         }
04073 #endif
04074 
04075         // return to double-sided lighting mode if we switched
04076         if (!cmd->doublesided) {
04077           glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_TRUE);
04078         }
04079         }
04080         break;
04081 
04082       case DWIREMESH: 
04083         {
04084         // draw a wire mesh
04085         DispCmdWireMesh *cmd = (DispCmdWireMesh *) cmdptr;
04086         int ind = cmd->numlines * 2;
04087         float *cnv;
04088         int *l;
04089         cmd->getpointers(cnv, l);
04090 #if defined(GL_VERSION_1_1)
04091         if (!simplegraphics) {
04092           glInterleavedArrays(GL_C4F_N3F_V3F, 0, cnv);
04093 
04094 #if defined(GL_EXT_compiled_vertex_array) 
04095           if (ext->hascompiledvertexarrayext) {
04096             GLLOCKARRAYSEXT(0, cmd->numverts);
04097           }
04098 #endif
04099 
04100           glDrawElements(GL_LINES, ind, GL_UNSIGNED_INT, l);
04101 
04102 #if defined(GL_EXT_compiled_vertex_array) 
04103           if (ext->hascompiledvertexarrayext) {
04104             GLUNLOCKARRAYSEXT();
04105           }
04106 #endif
04107         } else {
04108 #endif
04109           int i, ind2;
04110           glBegin(GL_LINES);
04111           for (i=0; i<ind; i++) {
04112             ind2 = l[i] * 10;
04113              glColor3fv(cnv + ind2    );
04114             glNormal3fv(cnv + ind2 + 4);
04115             glVertex3fv(cnv + ind2 + 7);
04116           }
04117           glEnd();
04118 #if defined(GL_VERSION_1_1)
04119         }
04120 #endif
04121         }
04122         break;
04123 
04124       case DCYLINDER:
04125         {
04126         // draw a cylinder of given radius and resolution
04127         float *cmd = (float *)cmdptr; 
04128         cylinder_full((int)(cmd[7]), cmd+9, (int)(cmd[8]));
04129         } 
04130         break;
04131 
04132       case DCONE:
04133         {
04134         DispCmdCone *cmd = (DispCmdCone *)cmdptr;
04135         // draw a cone of given radius and resolution
04136         cylinder(cmd->pos2, cmd->pos1, cmd->res, cmd->radius, cmd->radius2);
04137         }
04138         break;
04139 
04140       case DTEXTSIZE:
04141         textsize = ((DispCmdTextSize *)cmdptr)->size;
04142         break;
04143 
04144       case DTEXTOFFSET:
04145         textoffset_x = ((DispCmdTextOffset *)cmdptr)->x;
04146         textoffset_y = ((DispCmdTextOffset *)cmdptr)->y;
04147         break;
04148 
04149       case DTEXT:
04150         {
04151         float *pos = (float *)cmdptr;        
04152         float thickness = pos[3];   // thickness is stored in 4th element
04153         char *txt = (char *)(pos+4);
04154         float wp[4];
04155         float mp[4] = { 0, 0, 0, 1};
04156 
04157 #ifdef VMDWIREGL
04158         // WireGL doesn't suppor the glPushAttrib() function, so these are
04159         // variables used to save current OpenGL state prior to 
04160         // clobbering it with new state, so we can return properly.
04161         GLfloat   tmppointSize;
04162         GLfloat   tmplineWidth;
04163         GLboolean tmplineStipple;
04164         GLint     tmplineSRepeat;
04165         GLint     tmplineSPattern;
04166 #endif
04167 
04168         mp[0] = pos[0]; mp[1] = pos[1]; mp[2] = pos[2];
04169         textMat.multpoint4d(mp,wp);
04170 
04171         glPushMatrix();
04172           glLoadIdentity();
04173           glMatrixMode(GL_PROJECTION);
04174           glPushMatrix();
04175             glLoadIdentity();
04176             glTranslatef((wp[0]+textoffset_x)/wp[3], 
04177                          (wp[1]+textoffset_y)/wp[3], 
04178                           wp[2]/wp[3]);
04179 
04180             glScalef(textsize/Aspect,textsize,textsize);
04181 
04182 #ifdef VMDWIREGL
04183               glGetFloatv(GL_POINT_SIZE,          &tmppointSize   );
04184               glGetFloatv(GL_LINE_WIDTH,          &tmplineWidth   );
04185             glGetIntegerv(GL_LINE_STIPPLE_REPEAT, &tmplineSRepeat );
04186             glGetIntegerv(GL_LINE_STIPPLE_PATTERN,&tmplineSPattern);
04187             tmplineStipple = glIsEnabled(GL_LINE_STIPPLE);
04188 #else
04189             glPushAttrib(GL_LINE_BIT | GL_POINT_BIT);
04190 #endif
04191 
04192             // enable line antialiasing, looks much nicer, may run slower
04193             glEnable(GL_BLEND);
04194             glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
04195             glEnable(GL_LINE_SMOOTH);
04196 
04197 // #define VMDMSAAFONTTOGGLE 1
04198 
04199             // MSAA lines with widths > 1.0 can look bad at low sample counts
04200             // so we either toggle MSAA off/on, or we have to stick to lines
04201             // of 1.0 pixels in width.
04202 #if defined(VMDMSAAFONTTOGGLE)
04203 #if defined(GL_ARB_multisample)
04204             // Toggle MSAA off/on on-the-fly
04205             if (aaEnabled) {
04206               glDisable(GL_MULTISAMPLE_ARB);
04207             }
04208             glLineWidth(thickness);
04209             glPointSize(thickness * 0.95f); // scale down point size by a hair
04210 #endif 
04211 #else 
04212             glLineWidth(thickness);
04213             glPointSize(thickness * 0.95f); // scale down point size by a hair
04214 #endif
04215 
04216             glDisable(GL_LINE_STIPPLE);
04217             if (thickness > 2.0f)
04218               glListBase(fontNpxListBase); // font stroke vectors only
04219             else
04220               glListBase(font1pxListBase); // font stroke vectors+points
04221 
04222             glCallLists(strlen(txt), GL_UNSIGNED_BYTE, (GLubyte *)txt);
04223 
04224 #if defined(VMDMSAAFONTTOGGLE)
04225 #if defined(GL_ARB_multisample)
04226             // Toggle MSAA off/on on-the-fly
04227             if (aaEnabled) {
04228               glEnable(GL_MULTISAMPLE_ARB);
04229             }
04230 #endif 
04231 #endif
04232 
04233             // disable line antialiasing, return to normal mode 
04234             glDisable(GL_BLEND);
04235             glDisable(GL_LINE_SMOOTH);
04236 
04237 #ifdef VMDWIREGL
04238             glLineWidth(tmplineWidth);
04239             glPointSize(tmppointSize);
04240             glLineStipple(tmplineSRepeat, (GLushort) tmplineSPattern);
04241             if (tmplineStipple == GL_TRUE)
04242                glEnable(GL_LINE_STIPPLE);
04243             else
04244                glDisable(GL_LINE_STIPPLE);
04245 #else
04246             glPopAttrib();
04247 #endif
04248 
04249 
04250           glPopMatrix();
04251           glMatrixMode(GL_MODELVIEW);
04252         glPopMatrix();
04253         }
04254         break;
04255 
04256       case DCOLORINDEX:
04257         // set the current color to the given color index ... assumes the
04258         // color has already been defined
04259         glColor3fv((GLfloat *)(colorData+3*(((DispCmdColorIndex *)cmdptr)->color)));
04260         break;
04261 
04262       case DMATERIALON:
04263         glEnable(GL_LIGHTING);
04264         ogl_lightingenabled=1;
04265 #if defined(VMDUSEOPENGLSHADER)
04266         if (mainshader && ogl_useglslshader) {
04267           mainshader->UseShader(1); // use glsl mainshader when shading is on
04268         }
04269 #endif
04270         break;
04271 
04272       case DMATERIALOFF:
04273         glDisable(GL_LIGHTING);
04274         ogl_lightingenabled=0;
04275 #if defined(VMDUSEOPENGLSHADER)
04276         if (mainshader && ogl_useglslshader) {
04277           mainshader->UseShader(0); // use fixed-func pipeline when shading is off
04278         }
04279 #endif
04280         break;
04281 
04282       case DSPHERERES:
04283         // set the current sphere resolution
04284         set_sphere_res(((DispCmdSphereRes *)cmdptr)->res);
04285         break;
04286 
04287       case DSPHERETYPE:
04288         // set the current sphere type
04289         set_sphere_mode(((DispCmdSphereType *)cmdptr)->type);
04290         break;
04291 
04292       case DLINESTYLE: 
04293         // set the current line style
04294         set_line_style(((DispCmdLineType *)cmdptr)->type);
04295         break;
04296 
04297       case DLINEWIDTH: 
04298         // set the current line width
04299         set_line_width(((DispCmdLineWidth *)cmdptr)->width);
04300         break;
04301 
04302       case DPICKPOINT:
04303       case DPICKPOINT_ARRAY:
04304       default:
04305         // msgErr << "OpenGLRenderer: Unknown drawing token " << tok
04306         //        << " encountered ... Skipping this command." << sendmsg;
04307         break;
04308 
04309     } 
04310   }
04311  
04312   } // XXX code to run render loop or not
04313 
04314   // Tail end of display list caching code
04315   if (ogl_cacheenabled && (!ogl_cacheskip)) { 
04316     if (ogl_cachecreated) {
04317       glEndList();              // finish off display list we're creating
04318     } else {
04319       if (ogl_cachedebug) {
04320         msgInfo << "Calling cached geometry: id=" << (int)ogl_cachedid << sendmsg;
04321       }
04322       glCallList(ogl_cachedid); // call the display list we previously cached
04323     }
04324   }
04325 
04326 
04327   glPopMatrix();
04328 } // end loop over instance images
04329 
04330   glPopMatrix();
04331 } // end loop over periodic images
04332 
04333   // restore transformation matrix
04334   glPopMatrix();
04335 }
04336 
04337 void OpenGLRenderer::render_done() {
04338   ogl_glsltoggle = 1; // force GLSL update next time through
04339 
04340   GLuint tag;
04341   // delete all unused display lists
04342   while ((tag = displaylistcache.deleteUnused()) != GLCACHE_FAIL) {
04343     glDeleteLists(tag, 1);
04344   }
04345 
04346   // delete all unused textures
04347   while ((tag = texturecache.deleteUnused()) != GLCACHE_FAIL) {
04348     glDeleteTextures(1, &tag);
04349   }
04350 }
04351 
04352 void OpenGLRenderer::require_volume_texture(unsigned long ID,
04353     unsigned xsize, unsigned ysize, unsigned zsize,
04354     unsigned char *texmap) {
04355 
04356   if (!ext->hastex3d) return;
04357   GLuint texName;
04358   if ((texName = texturecache.markUsed(ID)) == 0) {
04359     glGenTextures(1, &texName);
04360     texturecache.encache(ID, texName); // cache this texture ID
04361     glBindTexture(GL_TEXTURE_3D, texName);
04362 
04363     // set texture border color to black
04364     GLfloat texborder[4] = {0.0, 0.0, 0.0, 1.0};
04365     glTexParameterfv(GL_TEXTURE_3D, GL_TEXTURE_BORDER_COLOR, texborder);
04366 
04367     // use the border color when wrapping at the edge
04368     glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_R, GL_CLAMP);
04369     glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_S, GL_CLAMP);
04370     glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_T, GL_CLAMP);
04371 
04372     // enable texture interpolation and filtering
04373     glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
04374     glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
04375 
04376     if (build3Dmipmaps(xsize, ysize, zsize, texmap)) {
04377       msgErr << "OpenGLRenderer failed to download 3-D texture map!" 
04378              << sendmsg; 
04379     }
04380   } else { // already cached, so just enable.
04381     glBindTexture(GL_TEXTURE_3D, texName);
04382   }
04383 }
04384 
04385 
04386 int OpenGLRenderer::build3Dmipmaps(int width, int height, int depth, unsigned char *tx) {
04387 #if defined(GL_VERSION_1_2)
04388   if (ext->hastex3d) {
04389     int xsize=width;
04390     int ysize=height;
04391     int zsize=depth;
04392     int xstep=1;
04393     int ystep=1;
04394     int zstep=1;
04395     int x,y,z;
04396 
04397     if (tx == NULL) {
04398       msgErr << "Skipping MIP map generation for NULL 3-D texture map" 
04399              << sendmsg;
04400       return 1;
04401     } 
04402 
04403     // build Mipmaps if the card can't handle the full resolution texture map
04404     if (xsize > max3DtexX || ysize > max3DtexY || zsize > max3DtexZ) { 
04405       unsigned char *texmap;
04406 
04407       while (xsize > max3DtexX) {
04408         xsize >>= 1;
04409         xstep <<= 1;
04410       }
04411   
04412       while (ysize > max3DtexY) {
04413         ysize >>= 1;
04414         ystep <<= 1;
04415       }
04416 
04417       while (zsize > max3DtexZ) {
04418         zsize >>= 1; 
04419         zstep <<= 1;
04420       }
04421 
04422       if (xsize == 0 || ysize == 0 || zsize == 0)
04423         return 1; // error, can't subsample the image down to required res
04424 
04425       texmap = (unsigned char *) malloc(xsize*ysize*zsize*3);
04426       if (texmap == NULL) {
04427         msgErr << "Failed to allocate MIP map for downsampled texture" 
04428                << sendmsg;
04429         return 1; // failed allocation
04430       }
04431 
04432 #if 0
04433       // XXX draw a checkerboard texture until the MIPmap code is finished
04434       msgError << "3-D texture map can't fit into accelerator memory, aborted."
04435                << sendmsg;
04436 
04437       for (z=0; z<zsize; z++) {
04438         for (y=0; y<ysize; y++) {
04439           int addr = z*xsize*ysize + y*xsize;
04440           for (x=0; x<xsize; x++) {
04441             if ((x + y + z) % 2) {
04442               texmap[(addr + x)*3    ] = 0;
04443               texmap[(addr + x)*3 + 1] = 0;
04444               texmap[(addr + x)*3 + 2] = 0;
04445             } else {
04446               texmap[(addr + x)*3    ] = 255;
04447               texmap[(addr + x)*3 + 1] = 255;
04448               texmap[(addr + x)*3 + 2] = 255;
04449             }
04450           }
04451         }
04452       }
04453 
04454 #else
04455       msgInfo << "Downsampling 3-D texture map from " 
04456               << width << "x" << height << "x" << depth << " to " 
04457               << xsize << "x" << ysize << "x" << zsize << sendmsg;
04458                
04459       for (z=0; z<zsize; z++) {
04460         for (y=0; y<ysize; y++) {
04461           int addr = z*xsize*ysize + y*xsize;
04462           for (x=0; x<xsize; x++) {
04463             int sumR=0, sumG=0, sumB=0;
04464             int texelcount = 0;
04465             int ox, oxs, oxe;
04466             int oy, oys, oye;
04467             int oz, ozs, oze;
04468 
04469             oxs = x * xstep;
04470             oys = y * ystep;
04471             ozs = z * zstep;
04472 
04473             oxe = oxs + xstep;
04474             oye = oys + ystep;
04475             oze = ozs + zstep;
04476             if (oxe > width) oxe=width;
04477             if (oye > height) oye=height;
04478             if (oze > depth) oze=depth;
04479 
04480             for (oz=ozs; oz<oze; oz++) {
04481               for (oy=oys; oy<oye; oy++) {
04482                 int oaddr = oz*width*height + oy*width;
04483                 for (ox=oxs; ox<oxe; ox++) {
04484                   int oadx = (oaddr + ox)*3;
04485                   sumR += tx[oadx    ];
04486                   sumG += tx[oadx + 1];
04487                   sumB += tx[oadx + 2];
04488                   texelcount++;
04489                 }
04490               }
04491             }
04492 
04493             int adx = (addr + x)*3;
04494             texmap[adx    ] = (unsigned char) (sumR / ((float) texelcount));
04495             texmap[adx + 1] = (unsigned char) (sumG / ((float) texelcount));
04496             texmap[adx + 2] = (unsigned char) (sumB / ((float) texelcount));
04497           }
04498         }
04499       }
04500 #endif
04501 
04502       glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
04503       GLTEXIMAGE3D(GL_TEXTURE_3D, 0, GL_RGB8, xsize, ysize, zsize,
04504                    0, GL_RGB, GL_UNSIGNED_BYTE, texmap);
04505 
04506       free(texmap); // free the generated texture map for now
04507     } else {
04508       glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
04509       GLTEXIMAGE3D(GL_TEXTURE_3D, 0, GL_RGB8, width, height, depth,
04510                    0, GL_RGB, GL_UNSIGNED_BYTE, tx);
04511     }
04512   
04513     return 0;
04514   }
04515 #endif
04516 
04517   return 1; // failed to render 3-D texture map
04518 }
04519 
04520 void OpenGLRenderer::update_shader_uniforms(void * voidshader, int forceupdate) {
04521 #if defined(VMDUSEOPENGLSHADER)
04522   OpenGLShader *sh = (OpenGLShader *) voidshader; 
04523   GLint loc;
04524 
04525   // Update GLSL projection mode (used to control normal flipping code)
04526   GLint vmdprojectionmode = (ogl_glslprojectionmode == DisplayDevice::PERSPECTIVE) ? 1 : 0;
04527   loc = GLGETUNIFORMLOCATIONARB(sh->ProgramObject, "vmdprojectionmode");
04528   GLUNIFORM1IARB(loc, vmdprojectionmode);
04529 
04530   // Update active GLSL texturing mode from cached state just in case
04531   GLint vmdtexturemode = ogl_glsltexturemode;
04532   loc = GLGETUNIFORMLOCATIONARB(sh->ProgramObject, "vmdtexturemode");
04533   GLUNIFORM1IARB(loc, vmdtexturemode);
04534 
04535   // Update material parameters for OpenGL shader.
04536   // XXX unnecessary once references to gl_FrontMaterial.xxx work
04537   GLfloat matparms[4];
04538   matparms[0] = oglambient;
04539   matparms[1] = ogldiffuse;
04540   matparms[2] = oglspecular;
04541   matparms[3] = oglshininess;
04542   loc = GLGETUNIFORMLOCATIONARB(sh->ProgramObject, "vmdmaterial");
04543   GLUNIFORM4FVARB(loc, 1, matparms);
04544 
04545   // Set vmdopacity uniform used for alpha-blended transparency in GLSL  
04546   GLfloat vmdopacity[1];
04547   vmdopacity[0] = oglopacity;
04548   loc = GLGETUNIFORMLOCATIONARB(sh->ProgramObject, "vmdopacity");
04549   GLUNIFORM1FVARB(loc, 1, vmdopacity);
04550 
04551   // Set GLSL outline magnitude and width
04552   GLfloat vmdoutline[1];
04553   vmdoutline[0] = ogloutline;
04554   loc = GLGETUNIFORMLOCATIONARB(sh->ProgramObject, "vmdoutline");
04555   GLUNIFORM1FVARB(loc, 1, vmdoutline);
04556 
04557   GLfloat vmdoutlinewidth[1];
04558   vmdoutlinewidth[0] = ogloutlinewidth;
04559   loc = GLGETUNIFORMLOCATIONARB(sh->ProgramObject, "vmdoutlinewidth");
04560   GLUNIFORM1FVARB(loc, 1, vmdoutlinewidth);
04561 
04562   // Set GLSL transparency rendering mode for active material
04563   loc = GLGETUNIFORMLOCATIONARB(sh->ProgramObject, "vmdtransmode");
04564   GLUNIFORM1IARB(loc, ogltransmode);
04565 
04566   // Set fog mode for shader using vmdfogmode uniform
04567   loc = GLGETUNIFORMLOCATIONARB(sh->ProgramObject, "vmdfogmode");
04568   GLUNIFORM1IARB(loc, ogl_fogmode);
04569 
04570   // Set active texture map index
04571   loc = GLGETUNIFORMLOCATIONARB(sh->ProgramObject, "vmdtex0");
04572   GLUNIFORM1IARB(loc, 0); // using texture unit 0
04573 
04574   // Update the main lighting state used by GLSL if it isn't the same
04575   // as what is currently set in the fixed-function pipeline.
04576   // XXX this code will not be necessary once vendors correctly implement
04577   //     references to gl_LightSource[n].position in GLSL shader
04578   if (forceupdate || (ogl_glslserial != ogl_rendstateserial)) {
04579     int i;
04580 
04581     if (!forceupdate) {
04582       // Once updated, no need to do it again
04583       ogl_glslserial = ogl_rendstateserial;
04584     }
04585 
04586     // Set light positions and pre-calculating Blinn halfway
04587     // vectors for use by the shaders
04588     for (i=0; i<DISP_LIGHTS; i++) {
04589       char varbuf[32];
04590       sprintf(varbuf, "vmdlight%d", i);
04591       GLint loc = GLGETUNIFORMLOCATIONARB(sh->ProgramObject, varbuf);
04592       GLUNIFORM3FVARB(loc, 1, &ogl_lightpos[i][0]);
04593 
04594       // calculate Blinn's halfway vector 
04595       // L = direction to light
04596       // V = direction to camera
04597       // H=normalize(L + V)
04598       float L[3], V[3];
04599       GLfloat Hvec[3];
04600       (transMat.top()).multpoint3d(&ogl_lightpos[i][0], L);
04601       vec_scale(V, -1.0, eyeDir);
04602       vec_normalize(V);
04603       Hvec[0] = L[0] + V[0];
04604       Hvec[1] = L[1] + V[1];
04605       Hvec[2] = L[2] + V[2];
04606       vec_normalize(Hvec);
04607       sprintf(varbuf, "vmdlight%dH", i);
04608       loc = GLGETUNIFORMLOCATIONARB(mainshader->ProgramObject, varbuf);
04609       GLUNIFORM3FVARB(loc, 1, Hvec);
04610     } 
04611 
04612     // Set light on/off state for shader as well, using pre-known uniforms
04613     // XXX this code assumes a max of 4 lights, due to the use of a 
04614     //     vec4 for storing the values, despite DISP_LIGHTS sizing 
04615     //     the array of light scales.
04616     loc = GLGETUNIFORMLOCATIONARB(sh->ProgramObject, "vmdlightscale");
04617     GLfloat vmdlightscale[DISP_LIGHTS];
04618     for (i=0; i<DISP_LIGHTS; i++) {
04619       vmdlightscale[i] = (float) ogl_lightstate[i];
04620     }
04621     GLUNIFORM4FVARB(loc, 1, vmdlightscale);
04622   }
04623 #endif
04624 }
04625 
04626 

Generated on Sun Dec 16 02:38:08 2018 for VMD (current) by doxygen1.2.14 written by Dimitri van Heesch, © 1997-2002