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.477 $      $Date: 2021/10/08 03:39:38 $
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, ind;
03177           glBegin(GL_POINTS);
03178           ind = 0;
03179           for (i=0; i<pa->numpoints; i++) {
03180             glColor3fv(&colors[ind]);
03181             glVertex3fv(&centers[ind]); 
03182             ind += 3;
03183           }
03184           glEnd();
03185 #if defined(GL_VERSION_1_1)
03186         }
03187 #endif
03188         }
03189         break;
03190 
03191       case DLITPOINTARRAY: 
03192         {
03193         DispCmdLitPointArray *pa = (DispCmdLitPointArray *)cmdptr;
03194         float *centers;
03195         float *normals;
03196         float *colors;
03197         pa->getpointers(centers, normals, colors);
03198 #if defined(GL_VERSION_1_1)
03199         if (!(simplegraphics || ogl_acrobat3dcapture)) {
03200           // Vertex array implementation 
03201           glEnableClientState(GL_VERTEX_ARRAY);
03202           glEnableClientState(GL_COLOR_ARRAY);
03203           glEnableClientState(GL_NORMAL_ARRAY);
03204           glVertexPointer(3, GL_FLOAT, 12, (void *) centers);
03205           glNormalPointer(GL_FLOAT, 12, (void *) normals);
03206           glColorPointer(3, GL_FLOAT, 12, (void *)  colors);
03207 
03208 #if defined(GL_EXT_compiled_vertex_array) 
03209           if (ext->hascompiledvertexarrayext) {
03210             GLLOCKARRAYSEXT(0, pa->numpoints);
03211           }
03212 #endif
03213 
03214           // set point size, enable blending and point antialiasing
03215           glPointSize(pa->size); 
03216           glEnable(GL_POINT_SMOOTH);
03217 
03218 #if defined(GL_ARB_point_parameters) 
03219           int dodepthscaling = 0;
03220           // enable distance based point attenuation
03221           if (ext->hasglpointparametersext  && (projection() == PERSPECTIVE)) {
03222             dodepthscaling = 1;
03223             GLfloat abc[4] = {0.0, 0.0, 1.0};
03224             GLPOINTPARAMETERFVARB(GL_POINT_DISTANCE_ATTENUATION_ARB, abc);
03225           }
03226 #endif
03227 
03228           glDrawArrays(GL_POINTS, 0, pa->numpoints);
03229 
03230 #if defined(GL_ARB_point_parameters) 
03231           // disable distance based point attenuation
03232           if (dodepthscaling) {
03233             GLfloat abc[4] = {1.0, 0.0, 0.0};
03234             GLPOINTPARAMETERFVARB(GL_POINT_DISTANCE_ATTENUATION_ARB, abc);
03235           }
03236 #endif
03237 
03238           // disable blending and point antialiasing
03239           glDisable(GL_BLEND);
03240           glDisable(GL_POINT_SMOOTH);
03241 
03242 #if defined(GL_EXT_compiled_vertex_array) 
03243           if (ext->hascompiledvertexarrayext) {
03244             GLUNLOCKARRAYSEXT();
03245           }
03246 #endif
03247 
03248           glPointSize(1.0); // reset point size to default
03249         } else {
03250 #endif
03251           // Immediate mode implementation 
03252           int i, ind;
03253           glBegin(GL_POINTS);
03254           ind = 0;
03255           for (i=0; i<pa->numpoints; i++) {
03256             glColor3fv(&colors[ind]);
03257             glNormal3fv(&normals[ind]); 
03258             glVertex3fv(&centers[ind]); 
03259             ind += 3;
03260           }
03261           glEnd();
03262 #if defined(GL_VERSION_1_1)
03263         }
03264 #endif
03265         }
03266         break;
03267 
03268       case DLINE:
03269         // plot a line
03270         glBegin(GL_LINES);
03271           glVertex3fv(((DispCmdLine *)cmdptr)->pos1);
03272           glVertex3fv(((DispCmdLine *)cmdptr)->pos2);
03273         glEnd();
03274         break;
03275 
03276       case DLINEARRAY:
03277         {
03278           float *v = (float *)(cmdptr);
03279           int nlines = (int)v[0];
03280           v++; // move pointer forward before traversing vertex data
03281 
03282 #if defined(GL_VERSION_1_1)
03283           if (!(simplegraphics || ogl_acrobat3dcapture)) {
03284             // Vertex array implementation
03285             glInterleavedArrays(GL_V3F, 0, v);
03286 
03287 #if defined(GL_EXT_compiled_vertex_array) 
03288             if (ext->hascompiledvertexarrayext) {
03289               GLLOCKARRAYSEXT(0, 2*nlines);
03290             }
03291 #endif
03292 
03293             glDrawArrays(GL_LINES, 0, 2*nlines); 
03294 
03295 #if defined(GL_EXT_compiled_vertex_array) 
03296             if (ext->hascompiledvertexarrayext) {
03297               GLUNLOCKARRAYSEXT();
03298             }
03299 #endif
03300           } else {
03301 #endif
03302             // Immediate mode implementation
03303             glBegin(GL_LINES);
03304             for (int i=0; i<nlines; i++) {
03305               glVertex3fv(v);
03306               glVertex3fv(v+3);
03307               v += 6;
03308             }
03309             glEnd();
03310 #if defined(GL_VERSION_1_1)
03311           }
03312 #endif
03313         }
03314         break;    
03315 
03316       case DPOLYLINEARRAY:
03317         {
03318           float *v = (float *)(cmdptr);
03319           int nverts = (int)v[0];
03320           v++; // move pointer forward before traversing vertex data
03321 
03322 #if defined(GL_VERSION_1_1)
03323           if (!(simplegraphics || ogl_acrobat3dcapture)) {
03324             // Vertex array implementation
03325             glInterleavedArrays(GL_V3F, 0, v);
03326 
03327 #if defined(GL_EXT_compiled_vertex_array) 
03328             if (ext->hascompiledvertexarrayext) {
03329               GLLOCKARRAYSEXT(0, nverts);
03330             }
03331 #endif
03332 
03333             glDrawArrays(GL_LINE_STRIP, 0, nverts); 
03334 
03335 #if defined(GL_EXT_compiled_vertex_array) 
03336             if (ext->hascompiledvertexarrayext) {
03337               GLUNLOCKARRAYSEXT();
03338             }
03339 #endif
03340           } else {
03341 #endif
03342             // Immediate mode implementation
03343             glBegin(GL_LINE_STRIP);
03344             for (int i=0; i<nverts; i++) {
03345               glVertex3fv(v);
03346               v += 3;
03347             }
03348             glEnd();
03349 #if defined(GL_VERSION_1_1)
03350           }
03351 #endif
03352         }
03353         break;    
03354 
03355       case DSPHERE: 
03356         {
03357         float *p = (float *)cmdptr;
03358         glPushMatrix();
03359         glTranslatef(p[0], p[1], p[2]); 
03360         glScalef(p[3], p[3], p[3]);
03361         glCallList(SphereList);
03362         glPopMatrix();
03363         }
03364         break;
03365 
03366       case DSPHEREARRAY: 
03367         {
03368         DispCmdSphereArray *sa = (DispCmdSphereArray *)cmdptr;
03369         int i, ind;
03370         float * centers;
03371         float * radii;
03372         float * colors;
03373         sa->getpointers(centers, radii, colors);
03374 
03375 #if defined(VMDUSEGLSLSPHERES) 
03376         // Render the sphere using programmable shading via ray-casting
03377         if (sphereshader && ogl_useglslshader) {
03378           // coordinates of unit bounding box
03379           GLfloat v0[] = {-1.0, -1.0, -1.0}; 
03380           GLfloat v1[] = { 1.0, -1.0, -1.0}; 
03381           GLfloat v2[] = {-1.0,  1.0, -1.0}; 
03382           GLfloat v3[] = { 1.0,  1.0, -1.0}; 
03383           GLfloat v4[] = {-1.0, -1.0,  1.0}; 
03384           GLfloat v5[] = { 1.0, -1.0,  1.0}; 
03385           GLfloat v6[] = {-1.0,  1.0,  1.0}; 
03386           GLfloat v7[] = { 1.0,  1.0,  1.0}; 
03387       
03388           mainshader->UseShader(0);   // switch to sphere shader
03389           sphereshader->UseShader(1); // switch to sphere shader
03390           update_shader_uniforms(sphereshader, 1); // force update of shader
03391 
03392           // Update projection parameters for OpenGL shader
03393           GLfloat projparms[4];
03394           projparms[0] = nearClip;
03395           projparms[1] = farClip; 
03396           projparms[2] = 0.5f * (farClip + nearClip);
03397           projparms[3] = 1.0f / (farClip - nearClip);
03398           GLint projloc = GLGETUNIFORMLOCATIONARB(sphereshader->ProgramObject, "vmdprojparms");
03399           GLUNIFORM4FVARB(projloc, 1, projparms);
03400           OGLERR;
03401 
03402           ind = 0;
03403           for (i=0; i<sa->numspheres; i++) {
03404             glPushMatrix();
03405             glTranslatef(centers[ind], centers[ind + 1], centers[ind + 2]); 
03406             glScalef(radii[i], radii[i], radii[i]);
03407             glColor3fv(&colors[ind]);
03408 
03409             // Draw the bounding box containing the sphere, gauranteeing 
03410             // that it will be correctly rendered regardless of the 
03411             // perspective projection used, viewing direction, etc.
03412             // If enough is known about the projection being used, this
03413             // could be done with simple billboard polygons, or perhaps even
03414             // a large OpenGL point primitive instead of a whole cube
03415             glBegin(GL_QUADS);
03416               glVertex3fv((GLfloat *) v0); /* -Z face */
03417               glVertex3fv((GLfloat *) v1);
03418               glVertex3fv((GLfloat *) v3);
03419               glVertex3fv((GLfloat *) v2);
03420 
03421               glVertex3fv((GLfloat *) v4); /* +Z face */
03422               glVertex3fv((GLfloat *) v5);
03423               glVertex3fv((GLfloat *) v7);
03424               glVertex3fv((GLfloat *) v6);
03425 
03426               glVertex3fv((GLfloat *) v0); /* -Y face */
03427               glVertex3fv((GLfloat *) v1);
03428               glVertex3fv((GLfloat *) v5);
03429               glVertex3fv((GLfloat *) v4);
03430 
03431               glVertex3fv((GLfloat *) v2); /* +Y face */
03432               glVertex3fv((GLfloat *) v3);
03433               glVertex3fv((GLfloat *) v7);
03434               glVertex3fv((GLfloat *) v6);
03435 
03436               glVertex3fv((GLfloat *) v0); /* -X face */
03437               glVertex3fv((GLfloat *) v2);
03438               glVertex3fv((GLfloat *) v6);
03439               glVertex3fv((GLfloat *) v4);
03440 
03441               glVertex3fv((GLfloat *) v1); /* +X face */
03442               glVertex3fv((GLfloat *) v3);
03443               glVertex3fv((GLfloat *) v7);
03444               glVertex3fv((GLfloat *) v5);
03445             glEnd();
03446             glPopMatrix();
03447             ind += 3; // next sphere
03448           }
03449 
03450           sphereshader->UseShader(0); // switch back to the main shader
03451           mainshader->UseShader(1);   // switch back to the main shader
03452           OGLERR;
03453         } else {
03454 #endif
03455           // OpenGL display listed sphere rendering implementation
03456           set_sphere_res(sa->sphereres); // set the current sphere resolution
03457 
03458           // use single-sided lighting when drawing spheres for 
03459           // peak rendering speed.
03460           glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_FALSE);
03461           ind = 0;
03462           for (i=0; i<sa->numspheres; i++) {
03463             glPushMatrix();
03464             glTranslatef(centers[ind], centers[ind + 1], centers[ind + 2]); 
03465             glScalef(radii[i], radii[i], radii[i]);
03466             glColor3fv(&colors[ind]);
03467             glCallList(SphereList);
03468             glPopMatrix();
03469             ind += 3; // next sphere
03470           }
03471           glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_TRUE);
03472 #if defined(VMDUSEGLSLSPHERES)
03473         }
03474 #endif
03475 
03476         }
03477         break;
03478 
03479       case DCUBEARRAY: 
03480         {
03481           DispCmdLatticeCubeArray *ca = (DispCmdLatticeCubeArray *)cmdptr;
03482           int i, ind;
03483           float * centers;
03484           float * radii;
03485           float * colors;
03486           ca->getpointers(centers, radii, colors);
03487 
03488           // Render the cube 
03489           // coordinates of unit cube
03490           GLfloat v0[] = {-1.0, -1.0, -1.0}; 
03491           GLfloat v1[] = { 1.0, -1.0, -1.0}; 
03492           GLfloat v2[] = {-1.0,  1.0, -1.0}; 
03493           GLfloat v3[] = { 1.0,  1.0, -1.0}; 
03494           GLfloat v4[] = {-1.0, -1.0,  1.0}; 
03495           GLfloat v5[] = { 1.0, -1.0,  1.0}; 
03496           GLfloat v6[] = {-1.0,  1.0,  1.0}; 
03497           GLfloat v7[] = { 1.0,  1.0,  1.0}; 
03498       
03499           ind = 0;
03500           for (i=0; i<ca->numcubes; i++) {
03501             glPushMatrix();
03502             glTranslatef(centers[ind], centers[ind + 1], centers[ind + 2]); 
03503             glScalef(radii[i], radii[i], radii[i]);
03504             glColor3fv(&colors[ind]);
03505 
03506             // Draw the unit cube
03507             glBegin(GL_QUADS);
03508               glNormal3f(0.0f, 0.0f, 1.0f);
03509               glVertex3fv((GLfloat *) v0); /* -Z face */
03510               glVertex3fv((GLfloat *) v1);
03511               glVertex3fv((GLfloat *) v3);
03512               glVertex3fv((GLfloat *) v2);
03513 
03514               glNormal3f(0.0f, 0.0f, 1.0f);
03515               glVertex3fv((GLfloat *) v4); /* +Z face */
03516               glVertex3fv((GLfloat *) v5);
03517               glVertex3fv((GLfloat *) v7);
03518               glVertex3fv((GLfloat *) v6);
03519 
03520               glNormal3f(0.0f, -1.0f, 0.0f);
03521               glVertex3fv((GLfloat *) v0); /* -Y face */
03522               glVertex3fv((GLfloat *) v1);
03523               glVertex3fv((GLfloat *) v5);
03524               glVertex3fv((GLfloat *) v4);
03525 
03526               glNormal3f(0.0f, -1.0f, 0.0f);
03527               glVertex3fv((GLfloat *) v2); /* +Y face */
03528               glVertex3fv((GLfloat *) v3);
03529               glVertex3fv((GLfloat *) v7);
03530               glVertex3fv((GLfloat *) v6);
03531 
03532               glNormal3f(1.0f, 0.0f, 0.0f);
03533               glVertex3fv((GLfloat *) v0); /* -X face */
03534               glVertex3fv((GLfloat *) v2);
03535               glVertex3fv((GLfloat *) v6);
03536               glVertex3fv((GLfloat *) v4);
03537 
03538               glNormal3f(1.0f, 0.0f, 0.0f);
03539               glVertex3fv((GLfloat *) v1); /* +X face */
03540               glVertex3fv((GLfloat *) v3);
03541               glVertex3fv((GLfloat *) v7);
03542               glVertex3fv((GLfloat *) v5);
03543             glEnd();
03544             glPopMatrix();
03545             ind += 3; // next sphere
03546           }
03547           OGLERR;
03548         }
03549         break;
03550 
03551       case DTRIANGLE: 
03552         {
03553         DispCmdTriangle *cmd = (DispCmdTriangle *)cmdptr;
03554         glBegin(GL_TRIANGLES);
03555           glNormal3fv(cmd->norm1);
03556           glVertex3fv(cmd->pos1);
03557           glNormal3fv(cmd->norm2);
03558           glVertex3fv(cmd->pos2);
03559           glNormal3fv(cmd->norm3);
03560           glVertex3fv(cmd->pos3);
03561         glEnd();
03562         }
03563         break;
03564 
03565       case DSQUARE:
03566         // draw a square, given the four points
03567         {
03568         DispCmdSquare *cmd = (DispCmdSquare *)cmdptr;
03569         glBegin(GL_QUADS);
03570           glNormal3fv((GLfloat *) cmd->norml);
03571           glVertex3fv((GLfloat *) cmd->pos1);
03572           glVertex3fv((GLfloat *) cmd->pos2);
03573           glVertex3fv((GLfloat *) cmd->pos3);
03574           glVertex3fv((GLfloat *) cmd->pos4);
03575         glEnd();
03576         }
03577         break;
03578 
03579 #if 0
03580       case DSTRIPETEX:
03581         if (ext->hastex3d) {
03582 #if defined(GL_VERSION_1_2)
03583 #define STRIPEWIDTH 32
03584           GLubyte stripeImage[4 * STRIPEWIDTH];
03585           GLuint texName = 0;
03586           // glGenTextures(1, &texName);
03587           int i;
03588           for (i=0; i<STRIPEWIDTH; i++) {
03589             stripeImage[4*i    ] = (GLubyte) ((i>4) ? 255 : 0); // R
03590             stripeImage[4*i + 1] = (GLubyte) ((i>4) ? 255 : 0); // G
03591             stripeImage[4*i + 2] = (GLubyte) ((i>4) ? 255 : 0); // B
03592             stripeImage[4*i + 3] = (GLubyte) 255;               // W
03593           }
03594 
03595           glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
03596           glBindTexture(GL_TEXTURE_1D, texName);
03597           glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_WRAP_S, GL_REPEAT);
03598           glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_WRAP_T, GL_REPEAT);
03599           glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_WRAP_R, GL_REPEAT);
03600           glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
03601           glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
03602           glTexImage1D(GL_TEXTURE_1D, 0, GL_RGBA, STRIPEWIDTH, 
03603                           0, GL_RGBA, GL_UNSIGNED_BYTE, stripeImage);
03604 
03605           // XXX should use GL_MODULATE, but requires all polygons to be
03606           //     drawn "white", in order for shading to make it through the
03607           //     texturing process.  GL_REPLACE works well for situations
03608           //     where we want coloring to come entirely from texture.
03609           glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
03610           GLfloat xplaneeq[4] = {0.5, 0.0, 0.0, 0.0};
03611           glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
03612           glTexGenfv(GL_S, GL_EYE_PLANE, xplaneeq);
03613           glEnable(GL_TEXTURE_GEN_S);
03614           glEnable(GL_TEXTURE_1D);
03615 #endif
03616         }
03617         break;
03618 
03619       case DSTRIPETEXOFF:
03620         if (ext->hastex3d) {
03621 #if defined(GL_VERSION_1_2)
03622           glDisable(GL_TEXTURE_GEN_S);
03623           glDisable(GL_TEXTURE_1D);
03624 #endif
03625         }
03626         break;
03627 #endif
03628 
03629       case DVOLUMETEXTURE:
03630         if (ext->hastex3d)
03631 #if defined(GL_VERSION_1_2)
03632         {
03633   
03634 #if defined(GL_GENERATE_MIPMAP_HINT)
03635           // set MIP map generation hint for high quality
03636           glHint(GL_GENERATE_MIPMAP_HINT, GL_NICEST);
03637 #endif
03638           glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
03639 
03640           DispCmdVolumeTexture *cmd = (DispCmdVolumeTexture *)cmdptr;
03641           require_volume_texture(cmd->ID, 
03642               cmd->xsize, cmd->ysize, cmd->zsize, 
03643               cmd->texmap);
03644 
03645           GLfloat xplaneeq[4]; 
03646           GLfloat yplaneeq[4]; 
03647           GLfloat zplaneeq[4]; 
03648           int i;
03649 
03650           glEnable(GL_TEXTURE_3D);
03651           glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
03652 
03653 #if defined(VMDUSEOPENGLSHADER)
03654           // Update active GLSL texturing mode
03655           if (mainshader && ogl_useglslshader) {
03656             if (!ogl_lightingenabled)
03657               mainshader->UseShader(1); // enable shader so state updates 
03658             ogl_glsltexturemode = 1;
03659             GLint vmdtexturemode = 1;  // enable 3-D texturing->MODULATE
03660             GLint loc = GLGETUNIFORMLOCATIONARB(mainshader->ProgramObject, "vmdtexturemode");
03661             GLUNIFORM1IARB(loc, vmdtexturemode);
03662       
03663             // Set active texture map index
03664             loc = GLGETUNIFORMLOCATIONARB(mainshader->ProgramObject, "vmdtex0");
03665             GLUNIFORM1IARB(loc, 0); // using texture unit 0
03666             if (!ogl_lightingenabled)
03667               mainshader->UseShader(0); // disable shader after state updates
03668           }
03669 #endif
03670 
03671           // automatically generate texture coordinates by translating from
03672           // model coordinate space to volume coordinates.  These aren't
03673           // going to be used by volume slices, but the performance hit
03674           // is expected to be insignificant.
03675           for (i=0; i<3; i++) {
03676             xplaneeq[i] = cmd->v1[i];
03677             yplaneeq[i] = cmd->v2[i];
03678             zplaneeq[i] = cmd->v3[i];
03679           }
03680           xplaneeq[3] = cmd->v0[0];
03681           yplaneeq[3] = cmd->v0[1];
03682           zplaneeq[3] = cmd->v0[2];
03683 
03684           glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR); 
03685           glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR); 
03686           glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR); 
03687           glTexGenfv(GL_S, GL_EYE_PLANE, xplaneeq);
03688           glTexGenfv(GL_T, GL_EYE_PLANE, yplaneeq);
03689           glTexGenfv(GL_R, GL_EYE_PLANE, zplaneeq);
03690           glEnable(GL_TEXTURE_GEN_S);
03691           glEnable(GL_TEXTURE_GEN_T);
03692           glEnable(GL_TEXTURE_GEN_R);
03693 #endif
03694         }
03695         break;
03696 
03697       case DVOLTEXON:
03698         if (ext->hastex3d) {
03699 #if defined(GL_VERSION_1_2)
03700           glEnable(GL_TEXTURE_3D);     // enable volume texturing
03701 #if defined(VMDUSEOPENGLSHADER)
03702           // Update active GLSL texturing mode
03703           if (mainshader && ogl_useglslshader) {
03704             if (!ogl_lightingenabled)
03705               mainshader->UseShader(1); // enable shader so state updates 
03706             ogl_glsltexturemode = 1;
03707             GLint vmdtexturemode = 1;  // enable 3-D texturing->MODULATE
03708             GLint loc = GLGETUNIFORMLOCATIONARB(mainshader->ProgramObject, "vmdtexturemode");
03709             GLUNIFORM1IARB(loc, vmdtexturemode);
03710             if (!ogl_lightingenabled)
03711               mainshader->UseShader(0); // disable shader after state updates
03712           }
03713 #endif
03714           glEnable(GL_TEXTURE_GEN_S);  // enable automatic texture 
03715           glEnable(GL_TEXTURE_GEN_T);  //   coordinate generation
03716           glEnable(GL_TEXTURE_GEN_R);
03717 #endif
03718         }
03719         break;
03720 
03721       case DVOLTEXOFF:
03722         if (ext->hastex3d) {
03723 #if defined(GL_VERSION_1_2)
03724           glDisable(GL_TEXTURE_3D);     // disable volume texturing
03725 #if defined(VMDUSEOPENGLSHADER)
03726           // Update active GLSL texturing mode
03727           if (mainshader && ogl_useglslshader) {
03728             if (!ogl_lightingenabled)
03729               mainshader->UseShader(1); // enable shader so state updates 
03730             ogl_glsltexturemode = 0;
03731             GLint vmdtexturemode = 0;  // disable 3-D texturing
03732             GLint loc = GLGETUNIFORMLOCATIONARB(mainshader->ProgramObject, "vmdtexturemode");
03733             GLUNIFORM1IARB(loc, vmdtexturemode);
03734             if (!ogl_lightingenabled)
03735               mainshader->UseShader(0); // disable shader after state updates
03736           }
03737 #endif
03738 
03739           glDisable(GL_TEXTURE_GEN_S);  // disable automatic texture 
03740           glDisable(GL_TEXTURE_GEN_T);  //   coordinate generation
03741           glDisable(GL_TEXTURE_GEN_R);
03742 #endif
03743         }
03744         break;
03745 
03746 
03747       case DVOLSLICE:
03748         if (ext->hastex3d) {
03749           DispCmdVolSlice *cmd = (DispCmdVolSlice *)cmdptr;
03750 #if defined(GL_VERSION_1_2)
03751 
03752           // DVOLUMETEXTURE does most of the work for us, but we override
03753           // a few of the texenv settings
03754           glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
03755 
03756           // enable or disable texture interpolation and filtering
03757           switch (cmd->texmode) {
03758             case 2:
03759               glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
03760               glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
03761               glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
03762               break;
03763 
03764             case 1:
03765               glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_DONT_CARE);
03766               glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
03767               glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
03768               break;
03769      
03770             case 0: 
03771             default:
03772               glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_FASTEST);
03773               glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
03774               glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
03775               break;
03776           }
03777       
03778           // use the texture edge colors rather border color when wrapping
03779           glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
03780           glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
03781           glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
03782 
03783 #if defined(VMDUSEOPENGLSHADER)
03784           // Update active GLSL texturing mode
03785           if (mainshader && ogl_useglslshader) {
03786             ogl_glsltexturemode = 2;
03787             GLint vmdtexturemode = 2;  // enable 3-D texturing->REPLACE
03788             GLint loc = GLGETUNIFORMLOCATIONARB(mainshader->ProgramObject, "vmdtexturemode");
03789             GLUNIFORM1IARB(loc, vmdtexturemode);
03790           }
03791 #endif
03792           glBegin(GL_QUADS);        
03793           for (int i=0; i<4; i++) {
03794             glNormal3fv(cmd->normal);
03795             glVertex3fv(cmd->v + 3*i);
03796           }
03797           glEnd();        
03798 #endif // GL_VERSION_1_2
03799         } 
03800         break;
03801 
03802       case DTRIMESH_C3F_N3F_V3F: 
03803         { 
03804         // draw a triangle mesh
03805         DispCmdTriMesh *cmd = (DispCmdTriMesh *) cmdptr;
03806         float *colors=NULL, *normals=NULL, *vertices=NULL;
03807 
03808         if (cmd->pervertexcolors)
03809           cmd->getpointers(colors, normals, vertices);
03810         else
03811           cmd->getpointers(normals, vertices);
03812 
03813 #if 1
03814 #if defined(GL_VERSION_1_1)
03815         if (!(simplegraphics || ogl_acrobat3dcapture)) {
03816           // Vertex array implementation
03817           if (cmd->pervertexcolors)
03818             glEnableClientState(GL_COLOR_ARRAY);
03819           else
03820             glDisableClientState(GL_COLOR_ARRAY);
03821           glEnableClientState(GL_NORMAL_ARRAY);
03822           glEnableClientState(GL_VERTEX_ARRAY);
03823 
03824           if (cmd->pervertexcolors)
03825             glColorPointer(3, GL_FLOAT, 0, (void *) colors);
03826           glNormalPointer(GL_FLOAT, 0, (void *) normals);
03827           glVertexPointer(3, GL_FLOAT, 0, (void *) vertices);
03828 
03829 #if defined(GL_EXT_compiled_vertex_array)
03830           if (ext->hascompiledvertexarrayext) {
03831             GLLOCKARRAYSEXT(0, cmd->numverts);
03832           }
03833 #endif
03834 
03835           glDrawArrays(GL_TRIANGLES, 0, cmd->numverts);
03836 
03837 #if defined(GL_EXT_compiled_vertex_array)
03838           if (ext->hascompiledvertexarrayext) {
03839             GLUNLOCKARRAYSEXT();
03840           }
03841 #endif
03842         } else {
03843 #endif
03844           // Immediate mode implementation
03845           int i, ind;
03846           glBegin(GL_TRIANGLES);
03847           ind = 0;
03848           if (cmd->pervertexcolors) {
03849             for (i=0; i<cmd->numverts; i++) {
03850               glColor3fv(&colors[ind]);
03851               glNormal3fv(&normals[ind]);
03852               glVertex3fv(&vertices[ind]);
03853               ind += 3;
03854             }
03855           } else {
03856             for (i=0; i<cmd->numverts; i++) {
03857               glNormal3fv(&normals[ind]);
03858               glVertex3fv(&vertices[ind]);
03859               ind += 3;
03860             }
03861           }
03862 
03863           glEnd();
03864 #if defined(GL_VERSION_1_1)
03865         }
03866 #endif
03867 
03868 #endif
03869         }
03870         break;
03871 
03872       case DTRIMESH_C4F_N3F_V3F: 
03873         {
03874         // draw a triangle mesh
03875         DispCmdTriMesh *cmd = (DispCmdTriMesh *) cmdptr;
03876         int ind = cmd->numfacets * 3;
03877         float *cnv;
03878         int *f;
03879         cmd->getpointers(cnv, f);
03880 
03881 #if defined(GL_VERSION_1_1)
03882         // Vertex array implementation
03883         if (!(simplegraphics || ogl_acrobat3dcapture)) {
03884           // If OpenGL 1.1, then use vertex arrays 
03885           glInterleavedArrays(GL_C4F_N3F_V3F, 0, cnv);
03886 
03887 #if defined(GL_EXT_compiled_vertex_array) 
03888           if (ext->hascompiledvertexarrayext) {
03889             GLLOCKARRAYSEXT(0, cmd->numverts);
03890           }
03891 #endif
03892 
03893           glDrawElements(GL_TRIANGLES, ind, GL_UNSIGNED_INT, f);
03894 
03895 #if defined(GL_EXT_compiled_vertex_array) 
03896           if (ext->hascompiledvertexarrayext) {
03897             GLUNLOCKARRAYSEXT();
03898           }
03899 #endif
03900         } else {
03901 #endif
03902 
03903           // simple graphics mode, but not Acrobat3D capture mode
03904           if (!ogl_acrobat3dcapture) {
03905             int i, ind2;
03906             glBegin(GL_TRIANGLES);
03907             for (i=0; i<ind; i++) {
03908               ind2 = f[i] * 10;
03909                glColor3fv(cnv + ind2    );
03910               glNormal3fv(cnv + ind2 + 4);
03911               glVertex3fv(cnv + ind2 + 7);
03912             }
03913             glEnd();
03914           } else { 
03915             // Version 7.0.9 of Acrobat3D can't capture multicolor
03916             // triangles, so we revert to averaged-single-color
03917             // triangles until they fix this capture bug.
03918             int i;
03919             for (i=0; i<cmd->numfacets; i++) {
03920               int ind = i * 3;
03921               float tmp[3], tmp2[3];
03922 
03923               int v0 = f[ind    ] * 10;
03924               int v1 = f[ind + 1] * 10;
03925               int v2 = f[ind + 2] * 10;
03926 
03927               vec_add(tmp, cnv + v0, cnv + v1);
03928               vec_add(tmp2, tmp, cnv + v2);
03929               vec_scale(tmp, 0.3333333f, tmp2);
03930               glBegin(GL_TRIANGLES);
03931               glColor3fv(tmp);
03932               glNormal3fv(cnv + v0 + 4);
03933               glVertex3fv(cnv + v0 + 7);
03934               glNormal3fv(cnv + v1 + 4);
03935               glVertex3fv(cnv + v1 + 7);
03936               glNormal3fv(cnv + v2 + 4);
03937               glVertex3fv(cnv + v2 + 7);
03938               glEnd();
03939             }
03940           }
03941 
03942 #if defined(GL_VERSION_1_1)
03943         }
03944 #endif
03945         }
03946         break;
03947 
03948 
03949       case DTRIMESH_C4U_N3F_V3F: 
03950         { 
03951         // draw a triangle mesh
03952         DispCmdTriMesh *cmd = (DispCmdTriMesh *) cmdptr;
03953         unsigned char *colors=NULL;
03954         float *normals=NULL, *vertices=NULL;
03955 
03956         if (cmd->pervertexcolors)
03957           cmd->getpointers(colors, normals, vertices);
03958         else
03959           cmd->getpointers(normals, vertices);
03960 
03961 #if 1
03962 #if defined(GL_VERSION_1_1)
03963         if (!(simplegraphics || ogl_acrobat3dcapture)) {
03964           // Vertex array implementation
03965           if (cmd->pervertexcolors)
03966             glEnableClientState(GL_COLOR_ARRAY);
03967           else
03968             glDisableClientState(GL_COLOR_ARRAY);
03969           glEnableClientState(GL_NORMAL_ARRAY);
03970           glEnableClientState(GL_VERTEX_ARRAY);
03971 
03972           if (cmd->pervertexcolors)
03973             glColorPointer(4, GL_UNSIGNED_BYTE, 0, (void *) colors);
03974           glNormalPointer(GL_FLOAT, 0, (void *) normals);
03975           glVertexPointer(3, GL_FLOAT, 0, (void *) vertices);
03976 
03977 #if defined(GL_EXT_compiled_vertex_array)
03978           if (ext->hascompiledvertexarrayext) {
03979             GLLOCKARRAYSEXT(0, cmd->numverts);
03980           }
03981 #endif
03982 
03983           glDrawArrays(GL_TRIANGLES, 0, cmd->numverts);
03984 
03985 #if defined(GL_EXT_compiled_vertex_array)
03986           if (ext->hascompiledvertexarrayext) {
03987             GLUNLOCKARRAYSEXT();
03988           }
03989 #endif
03990         } else {
03991 #endif
03992           // Immediate mode implementation
03993           int i, ind;
03994           glBegin(GL_TRIANGLES);
03995           ind = 0;
03996           if (cmd->pervertexcolors) {
03997             for (i=0; i<cmd->numverts; i++) {
03998               glColor3ubv(&colors[ind]);
03999               glNormal3fv(&normals[ind]);
04000               glVertex3fv(&vertices[ind]);
04001               ind += 3;
04002             }
04003           } else {
04004             for (i=0; i<cmd->numverts; i++) {
04005               glNormal3fv(&normals[ind]);
04006               glVertex3fv(&vertices[ind]);
04007               ind += 3;
04008             }
04009           }
04010 
04011           glEnd();
04012 #if defined(GL_VERSION_1_1)
04013         }
04014 #endif
04015 
04016 #endif
04017         }
04018         break;
04019 
04020 
04021       case DTRIMESH_C4U_N3B_V3F: 
04022         { 
04023         // draw a triangle mesh
04024         DispCmdTriMesh *cmd = (DispCmdTriMesh *) cmdptr;
04025         unsigned char *colors=NULL;
04026         signed char *normals=NULL;
04027         float *vertices=NULL;
04028 
04029         if (cmd->pervertexcolors)
04030           cmd->getpointers(colors, normals, vertices);
04031         else
04032           cmd->getpointers(normals, vertices);
04033 
04034 #if 1
04035 #if defined(GL_VERSION_1_1)
04036         if (!(simplegraphics || ogl_acrobat3dcapture)) {
04037           // Vertex array implementation
04038           if (cmd->pervertexcolors)
04039             glEnableClientState(GL_COLOR_ARRAY);
04040           else
04041             glDisableClientState(GL_COLOR_ARRAY);
04042           glEnableClientState(GL_NORMAL_ARRAY);
04043           glEnableClientState(GL_VERTEX_ARRAY);
04044 
04045           if (cmd->pervertexcolors)
04046             glColorPointer(4, GL_UNSIGNED_BYTE, 0, (void *) colors);
04047           glNormalPointer(GL_BYTE, 0, (void *) normals);
04048           glVertexPointer(3, GL_FLOAT, 0, (void *) vertices);
04049 
04050 #if defined(GL_EXT_compiled_vertex_array)
04051           if (ext->hascompiledvertexarrayext) {
04052             GLLOCKARRAYSEXT(0, cmd->numverts);
04053           }
04054 #endif
04055 
04056           glDrawArrays(GL_TRIANGLES, 0, cmd->numverts);
04057 
04058 #if defined(GL_EXT_compiled_vertex_array)
04059           if (ext->hascompiledvertexarrayext) {
04060             GLUNLOCKARRAYSEXT();
04061           }
04062 #endif
04063         } else {
04064 #endif
04065           // Immediate mode implementation
04066           int i, ind;
04067           glBegin(GL_TRIANGLES);
04068           ind = 0;
04069           if (cmd->pervertexcolors) {
04070             for (i=0; i<cmd->numverts; i++) {
04071               glColor3ubv(&colors[ind]);
04072               glNormal3bv((GLbyte *) &normals[ind]);
04073               glVertex3fv(&vertices[ind]);
04074               ind += 3;
04075             }
04076           } else {
04077             for (i=0; i<cmd->numverts; i++) {
04078               glNormal3bv((GLbyte *) &normals[ind]);
04079               glVertex3fv(&vertices[ind]);
04080               ind += 3;
04081             }
04082           }
04083 
04084           glEnd();
04085 #if defined(GL_VERSION_1_1)
04086         }
04087 #endif
04088 
04089 #endif
04090         }
04091         break;
04092 
04093         
04094       case DTRISTRIP: 
04095         {
04096         // draw triangle strips
04097         DispCmdTriStrips *cmd = (DispCmdTriStrips *) cmdptr;
04098         int numstrips = cmd->numstrips;
04099         int strip;
04100 
04101         float *cnv;
04102         int *f;
04103         int *vertsperstrip;
04104 
04105         cmd->getpointers(cnv, f, vertsperstrip);
04106 
04107         // use single-sided lighting when drawing possible, for
04108         // peak rendering speed.
04109         if (!cmd->doublesided) {
04110           glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_FALSE);
04111         }
04112 
04113 #if defined(GL_VERSION_1_1)
04114         if (!(simplegraphics || ogl_acrobat3dcapture)) {
04115           // If OpenGL 1.1, then use vertex arrays
04116           glInterleavedArrays(GL_C4F_N3F_V3F, 0, cnv);
04117 
04118 #if defined(GL_EXT_compiled_vertex_array) 
04119           if (ext->hascompiledvertexarrayext) {
04120             GLLOCKARRAYSEXT(0, cmd->numverts);
04121           }
04122 #endif
04123 
04124 #if defined(GL_EXT_multi_draw_arrays)
04125           // Try the Sun/ARB MultiDrawElements() extensions first.
04126           if (ext->hasmultidrawext) {
04127             int **indices = new int *[cmd->numstrips];
04128 
04129             // build array of facet list pointers to allow the renderer to
04130             // send everything in a single command/DMA when possible
04131             int qv=0;
04132             for (int i=0; i<numstrips; i++) {
04133               indices[i] = (int *) ((char *)f + qv * sizeof(int));
04134               qv += vertsperstrip[i]; // incr vertex index, next strip
04135             }
04136 
04137             GLMULTIDRAWELEMENTSEXT(GL_TRIANGLE_STRIP, 
04138                                    (GLsizei *) vertsperstrip, 
04139                                    GL_UNSIGNED_INT, 
04140                                    (const GLvoid **) indices, 
04141                                    numstrips);
04142 
04143             delete [] indices;
04144           }
04145           else  // if not MDE, then fall back to other techniques
04146 #endif
04147           // Use the regular OpenGL 1.1 vertex array APIs, loop over all strips
04148           {
04149             int qv=0;
04150             for (strip=0; strip < numstrips; strip++) {
04151               glDrawElements(GL_TRIANGLE_STRIP, vertsperstrip[strip],
04152                              GL_UNSIGNED_INT, (int *) ((char *) f + qv * sizeof(int)));
04153               qv += vertsperstrip[strip];
04154             }
04155           }
04156 
04157 #if defined(GL_EXT_compiled_vertex_array) 
04158           if (ext->hascompiledvertexarrayext) {
04159             GLUNLOCKARRAYSEXT();
04160           }
04161 #endif
04162         } else {
04163 #endif
04164           // simple graphics mode, but not Acrobat3D capture mode
04165           if (!ogl_acrobat3dcapture) {
04166             // No OpenGL 1.1? ouch, then we have to do this the slow way
04167             int t, ind;
04168             int v = 0; // current vertex index, initially 0
04169             // loop over all of the triangle strips
04170             for (strip=0; strip < numstrips; strip++) {         
04171               glBegin(GL_TRIANGLE_STRIP);
04172               // render all of the triangles in this strip
04173               for (t = 0; t < vertsperstrip[strip]; t++) {
04174                 ind = f[v] * 10;
04175                  glColor3fv(cnv + ind    );
04176                 glNormal3fv(cnv + ind + 4);
04177                 glVertex3fv(cnv + ind + 7);
04178                 v++; // increment vertex index, for the next triangle
04179               }
04180               glEnd();
04181             }
04182           } else {
04183             // Acrobat3D capture mode works around several bugs in the
04184             // capture utility provided with version 7.x.  Their capture
04185             // feature can't catch triangle strips, so we have to render
04186             // each of the triangles individually.
04187 
04188             // render triangle strips one triangle at a time
04189             // triangle winding order is:
04190             //   v0, v1, v2, then v2, v1, v3, then v2, v3, v4, etc.
04191             int strip, t, v = 0;
04192             int stripaddr[2][3] = { {0, 1, 2}, {1, 0, 2} };
04193 
04194             // loop over all of the triangle strips
04195             for (strip=0; strip < numstrips; strip++) {
04196               // loop over all triangles in this triangle strip
04197               glBegin(GL_TRIANGLES);
04198 
04199               for (t = 0; t < (vertsperstrip[strip] - 2); t++) {
04200                 // render one triangle, using lookup table to fix winding order
04201                 int v0 = f[v + (stripaddr[t & 0x01][0])] * 10;
04202                 int v1 = f[v + (stripaddr[t & 0x01][1])] * 10;
04203                 int v2 = f[v + (stripaddr[t & 0x01][2])] * 10;
04204 
04205 #if 1
04206                 // Version 7.0.9 of Acrobat3D can't capture multicolor
04207                 // triangles, so we revert to averaged-single-color
04208                 // triangles until they fix this capture bug.
04209                 float tmp[3], tmp2[3];
04210                 vec_add(tmp, cnv + v0, cnv + v1); 
04211                 vec_add(tmp2, tmp, cnv + v2); 
04212                 vec_scale(tmp, 0.3333333f, tmp2);
04213                 glColor3fv(tmp);
04214                 glNormal3fv(cnv + v0 + 4);
04215                 glVertex3fv(cnv + v0 + 7);
04216                 glNormal3fv(cnv + v1 + 4);
04217                 glVertex3fv(cnv + v1 + 7);
04218                 glNormal3fv(cnv + v2 + 4);
04219                 glVertex3fv(cnv + v2 + 7);
04220 #else
04221                  glColor3fv(cnv + v0    );
04222                 glNormal3fv(cnv + v0 + 4);
04223                 glVertex3fv(cnv + v0 + 7);
04224                  glColor3fv(cnv + v1    );
04225                 glNormal3fv(cnv + v1 + 4);
04226                 glVertex3fv(cnv + v1 + 7);
04227                  glColor3fv(cnv + v2    );
04228                 glNormal3fv(cnv + v2 + 4);
04229                 glVertex3fv(cnv + v2 + 7);
04230 #endif
04231 
04232                 v++; // move on to next vertex
04233               }
04234               glEnd();
04235               v+=2; // last two vertices are already used by last triangle
04236             }
04237           }
04238 
04239 #if defined(GL_VERSION_1_1)
04240         }
04241 #endif
04242 
04243         // return to double-sided lighting mode if we switched
04244         if (!cmd->doublesided) {
04245           glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_TRUE);
04246         }
04247         }
04248         break;
04249 
04250       case DWIREMESH: 
04251         {
04252         // draw a wire mesh
04253         DispCmdWireMesh *cmd = (DispCmdWireMesh *) cmdptr;
04254         int ind = cmd->numlines * 2;
04255         float *cnv;
04256         int *l;
04257         cmd->getpointers(cnv, l);
04258 #if defined(GL_VERSION_1_1)
04259         if (!simplegraphics) {
04260           glInterleavedArrays(GL_C4F_N3F_V3F, 0, cnv);
04261 
04262 #if defined(GL_EXT_compiled_vertex_array) 
04263           if (ext->hascompiledvertexarrayext) {
04264             GLLOCKARRAYSEXT(0, cmd->numverts);
04265           }
04266 #endif
04267 
04268           glDrawElements(GL_LINES, ind, GL_UNSIGNED_INT, l);
04269 
04270 #if defined(GL_EXT_compiled_vertex_array) 
04271           if (ext->hascompiledvertexarrayext) {
04272             GLUNLOCKARRAYSEXT();
04273           }
04274 #endif
04275         } else {
04276 #endif
04277           int i, ind2;
04278           glBegin(GL_LINES);
04279           for (i=0; i<ind; i++) {
04280             ind2 = l[i] * 10;
04281              glColor3fv(cnv + ind2    );
04282             glNormal3fv(cnv + ind2 + 4);
04283             glVertex3fv(cnv + ind2 + 7);
04284           }
04285           glEnd();
04286 #if defined(GL_VERSION_1_1)
04287         }
04288 #endif
04289         }
04290         break;
04291 
04292       case DCYLINDER:
04293         {
04294         // draw a cylinder of given radius and resolution
04295         float *cmd = (float *)cmdptr; 
04296         cylinder_full((int)(cmd[7]), cmd+9, (int)(cmd[8]));
04297         } 
04298         break;
04299 
04300 #if defined(VMDOPTIXRTRT)
04301       case DCYLINDERARRAY:
04302         {
04303         DispCmdCylinderArray *ca = (DispCmdCylinderArray *)cmdptr;
04304         float *points, *radii, *colors;
04305         ca->getpointers(points, radii, colors);
04306         int i,ind3,ind6;
04307         for (i=0,ind3=0,ind6=0; i<ca->numcylinders; i++,ind3+=3,ind6+=6) {
04308           glColor3fv(&colors[ind3]);
04309 //        cylinder_full(ca->cylinderres, points+ind6, radii[i], ca->cylindercaps);
04310           cylinder(points + ind6, points + ind6+3, ca->cylinderres,
04311                    radii[i], radii[i]);
04312 //, ca->cylindercaps);
04313         }
04314         }
04315         break;
04316 #endif
04317 
04318       case DCONE:
04319         {
04320         DispCmdCone *cmd = (DispCmdCone *)cmdptr;
04321         // draw a cone of given radius and resolution
04322         cylinder(cmd->pos2, cmd->pos1, cmd->res, cmd->radius, cmd->radius2);
04323         }
04324         break;
04325 
04326       case DTEXT:
04327         {
04328         float *pos = (float *)cmdptr;        
04329         float thickness = pos[3];   // thickness is stored in 4th element
04330         GLfloat textsize = pos[4];
04331         float textoffset_x = pos[5];
04332         float textoffset_y = pos[6];
04333         char *txt = (char *)(pos+7);
04334         float wp[4];
04335         float mp[4] = { 0, 0, 0, 1};
04336 
04337 #ifdef VMDWIREGL
04338         // WireGL doesn't suppor the glPushAttrib() function, so these are
04339         // variables used to save current OpenGL state prior to 
04340         // clobbering it with new state, so we can return properly.
04341         GLfloat   tmppointSize;
04342         GLfloat   tmplineWidth;
04343         GLboolean tmplineStipple;
04344         GLint     tmplineSRepeat;
04345         GLint     tmplineSPattern;
04346 #endif
04347 
04348         mp[0] = pos[0]; mp[1] = pos[1]; mp[2] = pos[2];
04349         textMat.multpoint4d(mp,wp);
04350 
04351         glPushMatrix();
04352           glLoadIdentity();
04353           glMatrixMode(GL_PROJECTION);
04354           glPushMatrix();
04355             glLoadIdentity();
04356             glTranslatef((wp[0]+textoffset_x)/wp[3], 
04357                          (wp[1]+textoffset_y)/wp[3], 
04358                           wp[2]/wp[3]);
04359 
04360             glScalef(textsize/Aspect,textsize,textsize);
04361 
04362 #ifdef VMDWIREGL
04363               glGetFloatv(GL_POINT_SIZE,          &tmppointSize   );
04364               glGetFloatv(GL_LINE_WIDTH,          &tmplineWidth   );
04365             glGetIntegerv(GL_LINE_STIPPLE_REPEAT, &tmplineSRepeat );
04366             glGetIntegerv(GL_LINE_STIPPLE_PATTERN,&tmplineSPattern);
04367             tmplineStipple = glIsEnabled(GL_LINE_STIPPLE);
04368 #else
04369             glPushAttrib(GL_LINE_BIT | GL_POINT_BIT);
04370 #endif
04371 
04372             // enable line antialiasing, looks much nicer, may run slower
04373             glEnable(GL_BLEND);
04374             glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
04375             glEnable(GL_LINE_SMOOTH);
04376 
04377 // #define VMDMSAAFONTTOGGLE 1
04378 
04379             // MSAA lines with widths > 1.0 can look bad at low sample counts
04380             // so we either toggle MSAA off/on, or we have to stick to lines
04381             // of 1.0 pixels in width.
04382 #if defined(VMDMSAAFONTTOGGLE)
04383 #if defined(GL_ARB_multisample)
04384             // Toggle MSAA off/on on-the-fly
04385             if (aaEnabled) {
04386               glDisable(GL_MULTISAMPLE_ARB);
04387             }
04388             glLineWidth(thickness);
04389             glPointSize(thickness * 0.95f); // scale down point size by a hair
04390 #endif 
04391 #else 
04392             glLineWidth(thickness);
04393             glPointSize(thickness * 0.95f); // scale down point size by a hair
04394 #endif
04395 
04396             glDisable(GL_LINE_STIPPLE);
04397             if (thickness > 2.0f)
04398               glListBase(fontNpxListBase); // font stroke vectors only
04399             else
04400               glListBase(font1pxListBase); // font stroke vectors+points
04401 
04402             glCallLists(strlen(txt), GL_UNSIGNED_BYTE, (GLubyte *)txt);
04403 
04404 #if defined(VMDMSAAFONTTOGGLE)
04405 #if defined(GL_ARB_multisample)
04406             // Toggle MSAA off/on on-the-fly
04407             if (aaEnabled) {
04408               glEnable(GL_MULTISAMPLE_ARB);
04409             }
04410 #endif 
04411 #endif
04412 
04413             // disable line antialiasing, return to normal mode 
04414             glDisable(GL_BLEND);
04415             glDisable(GL_LINE_SMOOTH);
04416 
04417 #ifdef VMDWIREGL
04418             glLineWidth(tmplineWidth);
04419             glPointSize(tmppointSize);
04420             glLineStipple(tmplineSRepeat, (GLushort) tmplineSPattern);
04421             if (tmplineStipple == GL_TRUE)
04422                glEnable(GL_LINE_STIPPLE);
04423             else
04424                glDisable(GL_LINE_STIPPLE);
04425 #else
04426             glPopAttrib();
04427 #endif
04428 
04429 
04430           glPopMatrix();
04431           glMatrixMode(GL_MODELVIEW);
04432         glPopMatrix();
04433         }
04434         break;
04435 
04436       case DCOLORINDEX:
04437         // set the current color to the given color index ... assumes the
04438         // color has already been defined
04439         glColor3fv((GLfloat *)(colorData+3*(((DispCmdColorIndex *)cmdptr)->color)));
04440         break;
04441 
04442       case DMATERIALON:
04443         glEnable(GL_LIGHTING);
04444         ogl_lightingenabled=1;
04445 #if defined(VMDUSEOPENGLSHADER)
04446         if (mainshader && ogl_useglslshader) {
04447           mainshader->UseShader(1); // use glsl mainshader when shading is on
04448         }
04449 #endif
04450         break;
04451 
04452       case DMATERIALOFF:
04453         glDisable(GL_LIGHTING);
04454         ogl_lightingenabled=0;
04455 #if defined(VMDUSEOPENGLSHADER)
04456         if (mainshader && ogl_useglslshader) {
04457           mainshader->UseShader(0); // use fixed-func pipeline when shading is off
04458         }
04459 #endif
04460         break;
04461 
04462       case DSPHERERES:
04463         // set the current sphere resolution
04464         set_sphere_res(((DispCmdSphereRes *)cmdptr)->res);
04465         break;
04466 
04467       case DSPHERETYPE:
04468         // set the current sphere type
04469         set_sphere_mode(((DispCmdSphereType *)cmdptr)->type);
04470         break;
04471 
04472       case DLINESTYLE: 
04473         // set the current line style
04474         set_line_style(((DispCmdLineType *)cmdptr)->type);
04475         break;
04476 
04477       case DLINEWIDTH: 
04478         // set the current line width
04479         set_line_width(((DispCmdLineWidth *)cmdptr)->width);
04480         break;
04481 
04482       case DPICKPOINT_ARRAY:
04483       default:
04484         // msgErr << "OpenGLRenderer: Unknown drawing token " << tok
04485         //        << " encountered ... Skipping this command." << sendmsg;
04486         break;
04487 
04488     } 
04489   }
04490  
04491   } // XXX code to run render loop or not
04492 
04493   // Tail end of display list caching code
04494   if (ogl_cacheenabled && (!ogl_cacheskip)) { 
04495     if (ogl_cachecreated) {
04496       glEndList();              // finish off display list we're creating
04497     } else {
04498       if (ogl_cachedebug) {
04499         msgInfo << "Calling cached geometry: id=" << (int)ogl_cachedid << sendmsg;
04500       }
04501       glCallList(ogl_cachedid); // call the display list we previously cached
04502     }
04503   }
04504 
04505 
04506   glPopMatrix();
04507 } // end loop over instance images
04508 
04509   glPopMatrix();
04510 } // end loop over periodic images
04511 
04512   // restore transformation matrix
04513   glPopMatrix();
04514 }
04515 
04516 void OpenGLRenderer::render_done() {
04517 #if defined(VMDOPTIXRTRT)
04518   if (ogl_optix_rtrt_passthrough) {
04519 //printf("OpenGLRenderer::render_done()\n");
04520 
04521     ort->scene_aggregation_complete(); // if 1st time, complete rendering setup
04522 
04523     ort->render_current_scene();
04524 
04525     unsigned char *imgrgb4u=NULL;
04526     ort->framebuffer_map_rgb4u(&imgrgb4u);
04527 
04528     if (imgrgb4u != NULL) {
04529       int xs=xSize;
04530       int ys=ySize;
04531 
04532       glPushMatrix();
04533       glDisable(GL_LIGHTING);           // disable lighting
04534       glDisable(GL_DEPTH_TEST);         // disable depth test
04535       glDepthMask(GL_FALSE);            // make Z-buffer read-only
04536 
04537       glViewport(0, 0, xs, ys);
04538 
04539 //      glShadeModel(GL_FLAT);
04540       glMatrixMode(GL_PROJECTION);
04541       glLoadIdentity();
04542       glOrtho(0.0, xs, 0.0, ys, -1.0, 1.0);
04543       glMatrixMode(GL_MODELVIEW);
04544 
04545       glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
04546 
04547 #if 0
04548       GLuint texName = 0;
04549       GLfloat texborder[4] = {0.0, 0.0, 0.0, 1.0};
04550       glBindTexture(GL_TEXTURE_2D, texName);
04551 
04552       /* black borders if we go rendering anything beyond texture coordinates */
04553       glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, texborder);
04554       glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
04555       glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
04556       glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
04557       glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
04558       glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
04559     
04560       glLoadIdentity();
04561       glColor3f(1.0, 1.0, 1.0);
04562 
04563       glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, xs, ys, 0,
04564                    GL_RGBA, GL_UNSIGNED_BYTE, imgrgb4u);
04565       glEnable(GL_TEXTURE_2D);
04566 
04567       glBegin(GL_QUADS);
04568       glTexCoord2f(0.0f, 0.0f);
04569       glVertex2f(0, 0);
04570       glTexCoord2f(0.0f, 1.0f);
04571       glVertex2f(0, GLfloat(ys));
04572       glTexCoord2f(1.0f, 1.0f);
04573       glVertex2f(GLfloat(xs), GLfloat(ys));
04574       glTexCoord2f(1.0f, 0.0f);
04575       glVertex2f(GLfloat(xs), 0.0f);
04576       glEnd();
04577 
04578       glDisable(GL_TEXTURE_2D);
04579 #else
04580       glPixelZoom(1.0, 1.0);
04581       glLoadIdentity();
04582       glRasterPos2i(0, 0);
04583       glDrawPixels(xs, ys, GL_RGBA, GL_UNSIGNED_BYTE, imgrgb4u);
04584 #endif
04585 
04586  //     glShadeModel(GL_SMOOTH);
04587       glDepthMask(GL_TRUE);              // make Z-buffer writeable
04588       glEnable(GL_DEPTH_TEST);           // enable Z-buffer test
04589       glEnable(GL_LIGHTING);             // restore lighting
04590       glPopMatrix();
04591     }
04592 
04593     ort->framebuffer_unmap();
04594   }
04595 #endif
04596 
04597   ogl_glsltoggle = 1; // force GLSL update next time through
04598 
04599   GLuint tag;
04600   // delete all unused display lists
04601   while ((tag = displaylistcache.deleteUnused()) != GLCACHE_FAIL) {
04602     glDeleteLists(tag, 1);
04603   }
04604 
04605   // delete all unused textures
04606   while ((tag = texturecache.deleteUnused()) != GLCACHE_FAIL) {
04607     glDeleteTextures(1, &tag);
04608   }
04609 }
04610 
04611 void OpenGLRenderer::require_volume_texture(unsigned long ID,
04612     unsigned xsize, unsigned ysize, unsigned zsize,
04613     unsigned char *texmap) {
04614 
04615   if (!ext->hastex3d) return;
04616   GLuint texName;
04617   if ((texName = texturecache.markUsed(ID)) == 0) {
04618     glGenTextures(1, &texName);
04619     texturecache.encache(ID, texName); // cache this texture ID
04620     glBindTexture(GL_TEXTURE_3D, texName);
04621 
04622     // set texture border color to black
04623     GLfloat texborder[4] = {0.0, 0.0, 0.0, 1.0};
04624     glTexParameterfv(GL_TEXTURE_3D, GL_TEXTURE_BORDER_COLOR, texborder);
04625 
04626     // use the border color when wrapping at the edge
04627     glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_R, GL_CLAMP);
04628     glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_S, GL_CLAMP);
04629     glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_T, GL_CLAMP);
04630 
04631     // enable texture interpolation and filtering
04632     glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
04633     glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
04634 
04635     if (build3Dmipmaps(xsize, ysize, zsize, texmap)) {
04636       msgErr << "OpenGLRenderer failed to download 3-D texture map!" 
04637              << sendmsg; 
04638     }
04639   } else { // already cached, so just enable.
04640     glBindTexture(GL_TEXTURE_3D, texName);
04641   }
04642 }
04643 
04644 
04645 int OpenGLRenderer::build3Dmipmaps(int width, int height, int depth, unsigned char *tx) {
04646 #if defined(GL_VERSION_1_2)
04647   if (ext->hastex3d) {
04648     int xsize=width;
04649     int ysize=height;
04650     int zsize=depth;
04651     int xstep=1;
04652     int ystep=1;
04653     int zstep=1;
04654     int x,y,z;
04655 
04656     if (tx == NULL) {
04657       msgErr << "Skipping MIP map generation for NULL 3-D texture map" 
04658              << sendmsg;
04659       return 1;
04660     } 
04661 
04662     // build Mipmaps if the card can't handle the full resolution texture map
04663     if (xsize > max3DtexX || ysize > max3DtexY || zsize > max3DtexZ) { 
04664       unsigned char *texmap;
04665 
04666       while (xsize > max3DtexX) {
04667         xsize >>= 1;
04668         xstep <<= 1;
04669       }
04670   
04671       while (ysize > max3DtexY) {
04672         ysize >>= 1;
04673         ystep <<= 1;
04674       }
04675 
04676       while (zsize > max3DtexZ) {
04677         zsize >>= 1; 
04678         zstep <<= 1;
04679       }
04680 
04681       if (xsize == 0 || ysize == 0 || zsize == 0)
04682         return 1; // error, can't subsample the image down to required res
04683 
04684       texmap = (unsigned char *) malloc(xsize*ysize*zsize*3);
04685       if (texmap == NULL) {
04686         msgErr << "Failed to allocate MIP map for downsampled texture" 
04687                << sendmsg;
04688         return 1; // failed allocation
04689       }
04690 
04691 #if 0
04692       // XXX draw a checkerboard texture until the MIPmap code is finished
04693       msgError << "3-D texture map can't fit into accelerator memory, aborted."
04694                << sendmsg;
04695 
04696       for (z=0; z<zsize; z++) {
04697         for (y=0; y<ysize; y++) {
04698           int addr = z*xsize*ysize + y*xsize;
04699           for (x=0; x<xsize; x++) {
04700             if ((x + y + z) % 2) {
04701               texmap[(addr + x)*3    ] = 0;
04702               texmap[(addr + x)*3 + 1] = 0;
04703               texmap[(addr + x)*3 + 2] = 0;
04704             } else {
04705               texmap[(addr + x)*3    ] = 255;
04706               texmap[(addr + x)*3 + 1] = 255;
04707               texmap[(addr + x)*3 + 2] = 255;
04708             }
04709           }
04710         }
04711       }
04712 
04713 #else
04714       msgInfo << "Downsampling 3-D texture map from " 
04715               << width << "x" << height << "x" << depth << " to " 
04716               << xsize << "x" << ysize << "x" << zsize << sendmsg;
04717                
04718       for (z=0; z<zsize; z++) {
04719         for (y=0; y<ysize; y++) {
04720           int addr = z*xsize*ysize + y*xsize;
04721           for (x=0; x<xsize; x++) {
04722             int sumR=0, sumG=0, sumB=0;
04723             int texelcount = 0;
04724             int ox, oxs, oxe;
04725             int oy, oys, oye;
04726             int oz, ozs, oze;
04727 
04728             oxs = x * xstep;
04729             oys = y * ystep;
04730             ozs = z * zstep;
04731 
04732             oxe = oxs + xstep;
04733             oye = oys + ystep;
04734             oze = ozs + zstep;
04735             if (oxe > width) oxe=width;
04736             if (oye > height) oye=height;
04737             if (oze > depth) oze=depth;
04738 
04739             for (oz=ozs; oz<oze; oz++) {
04740               for (oy=oys; oy<oye; oy++) {
04741                 int oaddr = oz*width*height + oy*width;
04742                 for (ox=oxs; ox<oxe; ox++) {
04743                   int oadx = (oaddr + ox)*3;
04744                   sumR += tx[oadx    ];
04745                   sumG += tx[oadx + 1];
04746                   sumB += tx[oadx + 2];
04747                   texelcount++;
04748                 }
04749               }
04750             }
04751 
04752             int adx = (addr + x)*3;
04753             texmap[adx    ] = (unsigned char) (sumR / ((float) texelcount));
04754             texmap[adx + 1] = (unsigned char) (sumG / ((float) texelcount));
04755             texmap[adx + 2] = (unsigned char) (sumB / ((float) texelcount));
04756           }
04757         }
04758       }
04759 #endif
04760 
04761       glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
04762       GLTEXIMAGE3D(GL_TEXTURE_3D, 0, GL_RGB8, xsize, ysize, zsize,
04763                    0, GL_RGB, GL_UNSIGNED_BYTE, texmap);
04764 
04765       free(texmap); // free the generated texture map for now
04766     } else {
04767       glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
04768       GLTEXIMAGE3D(GL_TEXTURE_3D, 0, GL_RGB8, width, height, depth,
04769                    0, GL_RGB, GL_UNSIGNED_BYTE, tx);
04770     }
04771   
04772     return 0;
04773   }
04774 #endif
04775 
04776   return 1; // failed to render 3-D texture map
04777 }
04778 
04779 void OpenGLRenderer::update_shader_uniforms(void * voidshader, int forceupdate) {
04780 #if defined(VMDUSEOPENGLSHADER)
04781   OpenGLShader *sh = (OpenGLShader *) voidshader; 
04782   GLint loc;
04783 
04784   // Update GLSL projection mode (used to control normal flipping code)
04785   GLint vmdprojectionmode = (ogl_glslprojectionmode == DisplayDevice::PERSPECTIVE) ? 1 : 0;
04786   loc = GLGETUNIFORMLOCATIONARB(sh->ProgramObject, "vmdprojectionmode");
04787   GLUNIFORM1IARB(loc, vmdprojectionmode);
04788 
04789   // Update active GLSL texturing mode from cached state just in case
04790   GLint vmdtexturemode = ogl_glsltexturemode;
04791   loc = GLGETUNIFORMLOCATIONARB(sh->ProgramObject, "vmdtexturemode");
04792   GLUNIFORM1IARB(loc, vmdtexturemode);
04793 
04794   // Update material parameters for OpenGL shader.
04795   // XXX unnecessary once references to gl_FrontMaterial.xxx work
04796   GLfloat matparms[4];
04797   matparms[0] = oglambient;
04798   matparms[1] = ogldiffuse;
04799   matparms[2] = oglspecular;
04800   matparms[3] = oglshininess;
04801   loc = GLGETUNIFORMLOCATIONARB(sh->ProgramObject, "vmdmaterial");
04802   GLUNIFORM4FVARB(loc, 1, matparms);
04803 
04804   // Set vmdopacity uniform used for alpha-blended transparency in GLSL  
04805   GLfloat vmdopacity[1];
04806   vmdopacity[0] = oglopacity;
04807   loc = GLGETUNIFORMLOCATIONARB(sh->ProgramObject, "vmdopacity");
04808   GLUNIFORM1FVARB(loc, 1, vmdopacity);
04809 
04810   // Set GLSL outline magnitude and width
04811   GLfloat vmdoutline[1];
04812   vmdoutline[0] = ogloutline;
04813   loc = GLGETUNIFORMLOCATIONARB(sh->ProgramObject, "vmdoutline");
04814   GLUNIFORM1FVARB(loc, 1, vmdoutline);
04815 
04816   GLfloat vmdoutlinewidth[1];
04817   vmdoutlinewidth[0] = ogloutlinewidth;
04818   loc = GLGETUNIFORMLOCATIONARB(sh->ProgramObject, "vmdoutlinewidth");
04819   GLUNIFORM1FVARB(loc, 1, vmdoutlinewidth);
04820 
04821   // Set GLSL transparency rendering mode for active material
04822   loc = GLGETUNIFORMLOCATIONARB(sh->ProgramObject, "vmdtransmode");
04823   GLUNIFORM1IARB(loc, ogltransmode);
04824 
04825   // Set fog mode for shader using vmdfogmode uniform
04826   loc = GLGETUNIFORMLOCATIONARB(sh->ProgramObject, "vmdfogmode");
04827   GLUNIFORM1IARB(loc, ogl_fogmode);
04828 
04829   // Set active texture map index
04830   loc = GLGETUNIFORMLOCATIONARB(sh->ProgramObject, "vmdtex0");
04831   GLUNIFORM1IARB(loc, 0); // using texture unit 0
04832 
04833   // Update the main lighting state used by GLSL if it isn't the same
04834   // as what is currently set in the fixed-function pipeline.
04835   // XXX this code will not be necessary once vendors correctly implement
04836   //     references to gl_LightSource[n].position in GLSL shader
04837   if (forceupdate || (ogl_glslserial != ogl_rendstateserial)) {
04838     int i;
04839 
04840     if (!forceupdate) {
04841       // Once updated, no need to do it again
04842       ogl_glslserial = ogl_rendstateserial;
04843     }
04844 
04845     // Set light positions and pre-calculating Blinn halfway
04846     // vectors for use by the shaders
04847     for (i=0; i<DISP_LIGHTS; i++) {
04848       char varbuf[32];
04849       sprintf(varbuf, "vmdlight%d", i);
04850       GLint loc = GLGETUNIFORMLOCATIONARB(sh->ProgramObject, varbuf);
04851       GLUNIFORM3FVARB(loc, 1, &ogl_lightpos[i][0]);
04852 
04853       // calculate Blinn's halfway vector 
04854       // L = direction to light
04855       // V = direction to camera
04856       // H=normalize(L + V)
04857       float L[3], V[3];
04858       GLfloat Hvec[3];
04859       (transMat.top()).multpoint3d(&ogl_lightpos[i][0], L);
04860       vec_scale(V, -1.0, eyeDir);
04861       vec_normalize(V);
04862       Hvec[0] = L[0] + V[0];
04863       Hvec[1] = L[1] + V[1];
04864       Hvec[2] = L[2] + V[2];
04865       vec_normalize(Hvec);
04866       sprintf(varbuf, "vmdlight%dH", i);
04867       loc = GLGETUNIFORMLOCATIONARB(mainshader->ProgramObject, varbuf);
04868       GLUNIFORM3FVARB(loc, 1, Hvec);
04869     } 
04870 
04871     // Set light on/off state for shader as well, using pre-known uniforms
04872     // XXX this code assumes a max of 4 lights, due to the use of a 
04873     //     vec4 for storing the values, despite DISP_LIGHTS sizing 
04874     //     the array of light scales.
04875     loc = GLGETUNIFORMLOCATIONARB(sh->ProgramObject, "vmdlightscale");
04876     GLfloat vmdlightscale[DISP_LIGHTS];
04877     for (i=0; i<DISP_LIGHTS; i++) {
04878       vmdlightscale[i] = (float) ogl_lightstate[i];
04879     }
04880     GLUNIFORM4FVARB(loc, 1, vmdlightscale);
04881   }
04882 #endif
04883 }
04884 
04885 

Generated on Mon Oct 25 02:47:57 2021 for VMD (current) by doxygen1.2.14 written by Dimitri van Heesch, © 1997-2002