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

OpenGLRenderer.C

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

Generated on Wed Jun 19 01:47:14 2013 for VMD (current) by doxygen1.2.14 written by Dimitri van Heesch, © 1997-2002