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

Generated on Wed Oct 9 02:42:59 2024 for VMD (current) by doxygen1.2.14 written by Dimitri van Heesch, © 1997-2002