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

OpenGLExtensions.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: OpenGLExtensions.C,v $
00013  *      $Author: johns $        $Locker:  $             $State: Exp $
00014  *      $Revision: 1.71 $       $Date: 2011/11/20 01:35:26 $
00015  *
00016  ***************************************************************************
00017  * DESCRIPTION:
00018  *   Class to store and handle enumeration and initialization of OpenGL 
00019  *   extensions and features.
00020  ***************************************************************************/
00021 
00022 #include <string.h>
00023 #include <stdlib.h>
00024 #include <stdio.h>
00025 #include <math.h>
00026 
00027 #include "OpenGLExtensions.h"
00028 #include "Inform.h"
00029 #include "utilities.h"
00030 
00031 #if !defined(_MSC_VER) && !(defined(__APPLE__) && !defined (VMDMESA))
00032 #include <GL/glx.h>     // needed for glxGetProcAddress() prototype
00033 #endif
00034 
00035 #if defined(__APPLE__)
00036 #import <mach-o/dyld.h> // needed by the getProcAddress code
00037 #import <string.h>
00038 #endif
00039 
00041 // constructor ... initialize some variables
00042 OpenGLExtensions::OpenGLExtensions(void) {
00043   // initialize OpenGL version info and feature detection
00044   multitextureunits = 0;
00045   hasmultisample = 0;
00046   hasmultidrawext = 0;
00047   hasstencilbuffer = 0;
00048   hastex2d = 0;
00049   hastex3d = 0;
00050   hasrescalenormalext = 0;
00051   hasglarbtexnonpoweroftwo = 0;
00052   hascompiledvertexarrayext = 0;
00053   hasglpointparametersext = 0;
00054   hasglpointspritearb = 0; 
00055   hasglshaderobjectsarb = 0;
00056   hasglshadinglangarb = 0;
00057   hasglvertexshaderarb = 0;
00058   hasglfragmentshaderarb = 0;
00059   hasglgeometryshader4arb = 0;
00060   hasglsampleshadingarb = 0;
00061 }
00062 
00063 // destructor
00064 OpenGLExtensions::~OpenGLExtensions(void) {
00065 }
00066 
00067 int OpenGLExtensions::vmdQueryExtension(const char *extname) {
00068   char *excl = getenv("VMD_EXCL_GL_EXTENSIONS");
00069   if (!extname)
00070     return 0;
00071 
00072   // search for extension in VMD's exclusion list  
00073   if (excl != NULL) {
00074     char *endexcl = excl + strlen(excl);
00075     while (excl < endexcl) {
00076       size_t n = strcspn(excl, " ");
00077       if ((strlen(extname) == n) && (strncmp(extname, excl, n) == 0)) {
00078         return 0; // extension is disabled and excluded
00079       }
00080       excl += (n + 1);
00081     }
00082   }
00083 
00084   // search for extension in list of available extensions
00085   char *ext = (char *) glGetString(GL_EXTENSIONS);
00086   if (ext != NULL) {
00087     char *endext = ext + strlen(ext);
00088     while (ext < endext) {
00089       size_t n = strcspn(ext, " ");
00090       if ((strlen(extname) == n) && (strncmp(extname, ext, n) == 0)) {
00091         return 1; // True, extension is available
00092         break;
00093       }
00094       ext += (n + 1);
00095     }
00096   }
00097 
00098   return 0; // False, extension is not available
00099 }
00100 
00101 VMDGLXextFuncPtr OpenGLExtensions::vmdGetProcAddress(const char * procname) {
00102   if (!procname)
00103     return NULL;
00104 
00105 #if defined(_MSC_VER)
00106   // NOTE: wgl returns a context-dependent function pointer
00107   //       the function can only be called within the same wgl
00108   //       context in which it was generated.
00109   return (VMDGLXextFuncPtr) wglGetProcAddress((LPCSTR) procname);
00110 #endif
00111 
00112 //
00113 // While this code often cratered on MacOS X 10.2, it seems to work fine with 
00114 // 10.4 on x86 (so far).  We'll turn it on and pray for the time being.
00115 // PowerPC builds still crater on some machines as of 10.4.7.
00116 //
00117 #if defined(__APPLE__)
00118 
00119 #if defined(ARCH_MACOSX)
00120   // MacOS X PowerPC versions still appear to be unstable with
00121   // the use of full OpenGL extensions.  So we turn them off at
00122   // at runtime unless the user has specifically enabled them.
00123   if (getenv("VMDMACENABLEEEXTENSIONS") == NULL) {
00124     return NULL;
00125   }
00126 #endif
00127 
00128   // According to the MacOS X documentation, they provide statically linkable
00129   // OpenGL extensions, which are made available as of various versions of OSX.
00130   // VMD will pick up whatever OpenGL extensions are available within the major
00131   // version of MacOS X that the binaries are compiled on for now.  Apple's
00132   // OpenGL extension docs are located here:
00133   //   http://developer.apple.com/opengl/extensions.html
00134   //
00135   // The newest MacOS X docs say you can do use this routine to find
00136   // OpenGL function entrypoints, among other methods:
00137   //   http://developer.apple.com/qa/qa2001/qa1188.html
00138   //   http://developer.apple.com/technotes/tn2002/tn2080.html#TAN55
00139   //   http://developer.apple.com/technotes/tn2002/tn2080.html#TAN28
00140 
00141   // MacOS X 10.3 and later supports the use of the Unix standard dlopen()
00142   // family of dynamic loading interfaces.  The current 10.4 related 
00143   // documentation suggests using these instead of the old interfaces.
00144   // In MacOS X 10.4.6, the NS* calls are deprecated and emit warnings at
00145   // compile time.
00146   
00147   // This implementation is based off of the MacOS X developer information
00148   // provided by Apple, circa MacOS X 10.2.  MacOS X 10.3 and 10.4 apps 
00149   // are directed to use the Unix standard dlopen() family of routines 
00150   // or to use explicit tests against weak-linked OpenGL API entry
00151   // points instead.  For now, we'll continue to use these routines since
00152   // they work and don't require hard coding framework names etc.
00153 #if 1 || !defined(ARCH_MACOSXX86_64)
00154   NSSymbol symbol;
00155   char *symbolName;
00156   // Prepend a '_' for the Unix C symbol mangling convention
00157   symbolName = (char *) calloc(1, strlen(procname) + 2);
00158   strcpy(symbolName+1, procname);
00159   symbolName[0] = '_';
00160   symbol = NULL;
00161   if (NSIsSymbolNameDefined(symbolName))
00162     symbol = NSLookupAndBindSymbol (symbolName);
00163   free(symbolName);
00164   return (VMDGLXextFuncPtr) (symbol ? NSAddressOfSymbol(symbol) : NULL);
00165 #endif
00166 #endif
00167 
00168 #if !defined(_MSC_VER) && !defined(__APPLE__)
00169 #if !defined(__linux) && !defined(ARCH_FREEBSD) && !defined(ARCH_FREEBSDAMD64) && !defined(ARCH_SOLARISX86) && !defined(ARCH_SOLARISX86_64) && (defined(GLX_VERSION_1_4) || defined(ARCH_SOLARIS2))
00170   // GLX 1.4 form found on commercial Unix systems that
00171   // don't bother providing the ARB extension version that Linux prefers.
00172   //
00173   // From FreeBSD ports comment by stephen@math.missouri.edu:
00174   // Why the !defined(ARCH_FREEBSD)?:  Typically the X libraries that
00175   // come with FreeBSD work with glXGetProcAddress.  However, if the
00176   // nvidia-driver port is installed, it seems not to work.  But using
00177   // glXGetProcAddressARB seems to work whether or not the nvidia-driver
00178   // port is installed.
00179   //
00180   return glXGetProcAddress((const GLubyte *) procname);
00181 #else
00182 
00183 // XXX this is a workaround for a crash on early 64-bit NVidia drivers
00184 #if defined(GLX_ARB_get_proc_address)
00185   // NOTE: GLX returns a context-independent function pointer that
00186   //       can be called anywhere, no special handling is required.
00187   //       This method is used on Linux
00188   return glXGetProcAddressARB((const GLubyte *) procname);
00189 #endif
00190 
00191 #endif
00192 #endif
00193 
00194   return NULL;
00195 }
00196 
00197 void OpenGLExtensions::vmdQueryGLVersion(int *major, int *minor, int *release) {
00198   const char *p = (char *) glGetString(GL_VERSION);
00199 
00200   *major = 1;
00201   *minor = 0;
00202   *release = 0;
00203 
00204   if (p != NULL) {
00205     char *cp;
00206     cp = (char *) calloc(1, strlen(p) + 1);
00207     strcpy(cp, p); 
00208   
00209     char *np=cp;
00210     char *ep=cp;
00211  
00212     while (np < (np + strlen(p))) {
00213       if (*np == ' ' || *np == '\0') {
00214         *np = '\0';
00215         ep = np;
00216         break;
00217       }
00218       np++;
00219     }
00220 
00221     np = cp;
00222     char *lp=cp;
00223     int x=0; 
00224     while (np <= ep) {
00225       if (*np == '.' || *np == '\0') {
00226         *np = '\0';
00227 
00228         switch(x) {
00229           case 0:
00230             *major = atoi(lp);
00231             break;
00232  
00233           case 1:
00234             *minor = atoi(lp);
00235             break;
00236  
00237           case 2:
00238             *release = atoi(lp);
00239             break;
00240         }
00241         np++;
00242         lp = np;
00243         x++;
00244         continue;
00245       }           
00246 
00247       np++;
00248     }
00249 
00250     free(cp);
00251   }
00252 }
00253 
00254 
00255 void OpenGLExtensions::find_renderer(void) {
00256   // Identify the hardware we're rendering on
00257   oglrenderer = GENERIC;
00258   const char * rs = (const char *) glGetString(GL_RENDERER);
00259   const char * rv = (const char *) glGetString(GL_VENDOR);
00260   if ((rs != NULL) && (rv != NULL)) { 
00261     if (strstr(rv, "ATI") != NULL) {
00262       oglrenderer = ATI;
00263     }
00264     if (strstr(rv, "NVIDIA") != NULL) {
00265       oglrenderer = NVIDIA;
00266     }
00267     if (strstr(rs, "GDI Generic") != NULL) {
00268       oglrenderer = MSOFTGDI; // microsoft software renderer
00269     }
00270     if (strstr(rs, "Mesa") != NULL) {
00271       oglrenderer = MESAGL;
00272     }
00273     if (strstr(rs, "WireGL") != NULL) {
00274       oglrenderer = WIREGL;
00275     }
00276   }
00277 }
00278 
00279 
00280 void OpenGLExtensions::find_extensions(void) {
00281   // initialize OpenGL extension function pointers to NULL
00282   p_glLockArraysEXT = NULL;
00283   p_glUnlockArraysEXT = NULL;
00284   p_glMultiDrawElementsEXT = NULL;
00285   p_glGlobalAlphaFactorfSUN = NULL;
00286   p_glPointParameterfARB = NULL;
00287   p_glPointParameterfvARB = NULL;
00288 
00289 #if defined(GL_ARB_shader_objects)
00290   // ARB OpenGL Shader functions
00291   p_glCreateShaderObjectARB = NULL;
00292   p_glCreateProgramObjectARB = NULL;
00293   p_glUseProgramObjectARB = NULL;
00294   p_glDetachObjectARB = NULL;
00295   p_glGetInfoLogARB = NULL;
00296   p_glGetObjectParameterivARB = NULL;
00297   p_glLinkProgramARB = NULL;
00298   p_glDeleteObjectARB = NULL;
00299   p_glAttachObjectARB = NULL;
00300   p_glCompileShaderARB = NULL;
00301   p_glShaderSourceARB = NULL;
00302   p_glGetUniformLocationARB = NULL;
00303   p_glUniform1iARB = NULL;
00304   p_glUniform1fvARB = NULL;
00305   p_glUniform2fvARB = NULL;
00306   p_glUniform3fvARB = NULL;
00307   p_glUniform4fvARB = NULL;
00308 #endif
00309 
00310   vmdQueryGLVersion(&oglmajor, &oglminor, &oglrelease);
00311 
00312   // check for an OpenGL stencil buffer
00313   GLint stencilbits;
00314   glGetIntegerv(GL_STENCIL_BITS, &stencilbits);
00315   if (stencilbits > 0) {
00316     hasstencilbuffer = 1;
00317   }
00318 
00319   // Identify the hardware we're rendering on
00320   find_renderer();
00321 
00322 #if defined(GL_ARB_multitexture)
00323   // perform tests for ARB multitexturing if we're on an
00324   // appropriate rev of OpenGL.
00325   if (((oglmajor >= 1) && (oglminor >= 2)) ||
00326       ((oglmajor >= 2) && (oglminor >= 0))) {
00327     // query to see if this machine supports the multitexture extension
00328     if (vmdQueryExtension("GL_ARB_multitexture")) {
00329       glGetIntegerv(GL_MAX_TEXTURE_UNITS_ARB, &multitextureunits);
00330     }
00331   }
00332 #endif
00333 
00334 #if defined(GL_VERSION_1_1)
00335   // Our implementation of 3-D texturing is only available on
00336   // OpenGL 1.1 or higher, so only enable/test if that is the case.
00337   if (((oglmajor >= 1) && (oglminor >= 1)) ||
00338       ((oglmajor >= 2) && (oglminor >= 0))) {
00339     hastex2d = 1;
00340   }
00341 #endif
00342 
00343 #if defined(GL_VERSION_1_2)
00344   // Our implementation of 3-D texturing is only available on
00345   // OpenGL 1.2 or higher, so only enable/test if that is the case.
00346   if (((oglmajor >= 1) && (oglminor >= 2)) ||
00347       ((oglmajor >= 2) && (oglminor >= 0))) {
00348 #if defined(VMDUSEGETPROCADDRESS) && !defined(__linux) && !defined(__APPLE__)
00349     p_glTexImage3D = (void (APIENTRY *)(GLenum, GLint, GLint,
00350                             GLsizei, GLsizei, GLsizei, GLint,
00351                             GLenum, GLenum, const GLvoid *)) vmdGetProcAddress("glTexImage3D"); 
00352     if (p_glTexImage3D != NULL) {
00353       hastex3d = 1;
00354     }
00355 #else
00356     hastex3d = 1;
00357 #endif
00358   }
00359 #endif
00360 
00361 #if defined(GL_ARB_texture_non_power_of_two)
00362   // check for ARB non-power-of-two texture size extension
00363   if (vmdQueryExtension("GL_ARB_texture_non_power_of_two")) {
00364     hasglarbtexnonpoweroftwo = 1;
00365   }
00366 #endif
00367 
00368 #if defined(GL_EXT_multi_draw_arrays)
00369   // check for the Sun/ARB glMultiDraw...() extensions
00370   if (vmdQueryExtension("GL_EXT_multi_draw_arrays")) {
00371 #if defined(VMDUSEGETPROCADDRESS)
00372     p_glMultiDrawElementsEXT = (void (APIENTRY *)(GLenum, const GLsizei *, GLenum, const GLvoid**, GLsizei)) vmdGetProcAddress("glMultiDrawElementsEXT");
00373     if (p_glMultiDrawElementsEXT != NULL) {
00374       hasmultidrawext = 1;
00375     } 
00376 #else 
00377     hasmultidrawext = 1;
00378 #endif    
00379   }
00380 #endif
00381 
00382 #if defined(GL_ARB_shading_language_100)
00383   // check for the OpenGL Shading Language extension
00384   if (vmdQueryExtension("GL_ARB_shading_language_100")) {
00385     hasglshadinglangarb = 1;
00386   }
00387 #endif
00388 
00389 #if defined(GL_ARB_shader_objects)
00390   if (vmdQueryExtension("GL_ARB_shader_objects")) {
00391 #if defined(VMDUSEGETPROCADDRESS)
00392     p_glCreateShaderObjectARB = (GLhandleARB (APIENTRY *)(GLenum)) vmdGetProcAddress("glCreateShaderObjectARB");
00393     p_glCreateProgramObjectARB = (GLhandleARB (APIENTRY *)(void)) vmdGetProcAddress("glCreateProgramObjectARB");
00394     p_glUseProgramObjectARB = (void (APIENTRY *)(GLhandleARB)) vmdGetProcAddress("glUseProgramObjectARB");
00395     p_glDetachObjectARB = (void (APIENTRY *)(GLhandleARB, GLhandleARB)) vmdGetProcAddress("glDetachObjectARB");
00396     p_glGetInfoLogARB = (void (APIENTRY *)(GLhandleARB, GLsizei, GLsizei *, GLcharARB *)) vmdGetProcAddress("glGetInfoLogARB");
00397     p_glGetObjectParameterivARB = (void (APIENTRY *)(GLhandleARB, GLenum, GLint *)) vmdGetProcAddress("glGetObjectParameterivARB");
00398     p_glLinkProgramARB = (void (APIENTRY *)(GLhandleARB)) vmdGetProcAddress("glLinkProgramARB");
00399     p_glDeleteObjectARB = (void (APIENTRY *)(GLhandleARB)) vmdGetProcAddress("glDeleteObjectARB");
00400     p_glAttachObjectARB = (void (APIENTRY *)(GLhandleARB, GLhandleARB)) vmdGetProcAddress("glAttachObjectARB");
00401     p_glCompileShaderARB = (void (APIENTRY *)(GLhandleARB)) vmdGetProcAddress("glCompileShaderARB");
00402     p_glShaderSourceARB = (void (APIENTRY *)(GLhandleARB, GLsizei, const GLcharARB **, const GLint *)) vmdGetProcAddress("glShaderSourceARB");
00403     p_glGetUniformLocationARB = (GLint (APIENTRY *)(GLhandleARB programObject, const GLcharARB *name)) vmdGetProcAddress("glGetUniformLocationARB");
00404     p_glUniform1iARB = (void (APIENTRY *)(GLint location, GLint v0)) vmdGetProcAddress("glUniform1iARB");
00405     p_glUniform1fvARB = (void (APIENTRY *)(GLint location, GLsizei count, GLfloat *value)) vmdGetProcAddress("glUniform1fvARB");
00406     p_glUniform2fvARB = (void (APIENTRY *)(GLint location, GLsizei count, GLfloat *value)) vmdGetProcAddress("glUniform2fvARB");
00407     p_glUniform3fvARB = (void (APIENTRY *)(GLint location, GLsizei count, GLfloat *value)) vmdGetProcAddress("glUniform3fvARB");
00408     p_glUniform4fvARB = (void (APIENTRY *)(GLint location, GLsizei count, GLfloat *value)) vmdGetProcAddress("glUniform4fvARB");
00409 
00410     if (p_glCreateShaderObjectARB != NULL && p_glCreateProgramObjectARB != NULL &&
00411         p_glUseProgramObjectARB != NULL && p_glDetachObjectARB != NULL &&
00412         p_glGetInfoLogARB != NULL && p_glGetObjectParameterivARB != NULL &&
00413         p_glLinkProgramARB != NULL && p_glDeleteObjectARB != NULL &&
00414         p_glAttachObjectARB != NULL && p_glCompileShaderARB != NULL &&
00415         p_glShaderSourceARB != NULL && p_glGetUniformLocationARB != NULL &&
00416         p_glUniform1iARB != NULL && p_glUniform1fvARB != NULL &&
00417         p_glUniform2fvARB != NULL && p_glUniform3fvARB != NULL && 
00418         p_glUniform4fvARB  != NULL) {
00419       hasglshaderobjectsarb = 1;
00420     } else {
00421       hasglshaderobjectsarb = 0;
00422     }  
00423 #else
00424     hasglshaderobjectsarb = 1;
00425 #endif
00426   }
00427 #endif
00428 
00429 #if defined(GL_ARB_vertex_shader)
00430   if (vmdQueryExtension("GL_ARB_vertex_shader")) {
00431     hasglvertexshaderarb = 1;
00432   }
00433 #endif
00434 
00435 #if defined(GL_ARB_fragment_shader)
00436   if (vmdQueryExtension("GL_ARB_fragment_shader")) {
00437     hasglfragmentshaderarb = 1;
00438   }
00439 #endif
00440 
00441 #if defined(GL_ARB_geometry_shader4)
00442   if (vmdQueryExtension("GL_ARB_geometry_shader4")) {
00443     hasglgeometryshader4arb = 1;
00444   }
00445 #endif
00446 
00447   if (vmdQueryExtension("GL_ARB_sample_shading")) {
00448     hasglsampleshadingarb = 1;
00449   }
00450 
00451 
00452 #if defined(GL_EXT_compiled_vertex_array)
00453   // check for the compiled vertex array extension
00454   if (vmdQueryExtension("GL_EXT_compiled_vertex_array")) {
00455 #if defined(VMDUSEGETPROCADDRESS)
00456     p_glLockArraysEXT   = (void (APIENTRY *)(GLint, GLsizei)) vmdGetProcAddress("glLockArraysEXT");
00457     p_glUnlockArraysEXT = (void (APIENTRY *)(void))           vmdGetProcAddress("glUnlockArraysEXT");
00458     if ((p_glLockArraysEXT != NULL) && (p_glUnlockArraysEXT != NULL)) { 
00459       hascompiledvertexarrayext = 1;
00460     }
00461 #else
00462     hascompiledvertexarrayext = 1;
00463 #endif
00464   }
00465 #endif
00466 
00467 #if defined(GL_ARB_point_parameters) 
00468   // check for glPointParameterfARB extension functions
00469   if (vmdQueryExtension("GL_ARB_point_parameters")) {
00470 #if defined(VMDUSEGETPROCADDRESS)
00471     p_glPointParameterfARB = (void (APIENTRY *)(GLenum, GLfloat)) vmdGetProcAddress("glPointParameterfARB");
00472     p_glPointParameterfvARB = (void (APIENTRY *)(GLenum, const GLfloat *)) vmdGetProcAddress("glPointParameterfvARB");
00473     if (p_glPointParameterfARB != NULL && p_glPointParameterfvARB != NULL) {
00474       hasglpointparametersext = 1;
00475     }
00476 #else
00477     hasglpointparametersext = 1;
00478 #endif
00479   } 
00480 #endif
00481 
00482 #if defined(GL_ARB_point_sprite)
00483   if (vmdQueryExtension("GL_ARB_point_sprite")) {
00484     hasglpointspritearb = 1;
00485   }
00486 #endif
00487 
00488 }
00489 
00490 
00491 void OpenGLExtensions::PrintExtensions(void) {
00492   const char * rs = (const char *) glGetString(GL_RENDERER);
00493   if (rs == NULL)
00494     rs = "ErrorUnknown";
00495 
00496   // Print renderer string for informational purposes
00497   msgInfo << "OpenGL renderer: " << rs << sendmsg;
00498 
00499   // print information on any OpenGL features found and used
00500   msgInfo << "  Features: ";
00501   if (hasstencilbuffer)
00502     msgInfo << "STENCIL ";
00503 
00504   if (hasstereo)
00505     msgInfo << "STEREO ";
00506 
00507   if (hasmultisample)
00508     msgInfo << "MSAA(" << nummultisamples << ") ";
00509 
00510   if (hasrescalenormalext)
00511     msgInfo << "RN ";
00512 
00513   if (hasmultidrawext)
00514     msgInfo << "MDE ";
00515 
00516   if (hascompiledvertexarrayext)
00517     msgInfo << "CVA ";
00518 
00519   if (multitextureunits > 0)
00520     msgInfo << "MTX ";
00521 
00522   if (hasglarbtexnonpoweroftwo)
00523     msgInfo << "NPOT ";
00524 
00525   if (hasglpointparametersext)
00526     msgInfo << "PP ";
00527 
00528   if (hasglpointspritearb)
00529     msgInfo << "PS "; 
00530 
00531   //
00532   // OpenGL Shading language extensions
00533   //
00534   if (hasglshadinglangarb) {
00535     msgInfo << "GLSL(";
00536 
00537     if (hasglshaderobjectsarb)
00538       msgInfo << "O"; 
00539 
00540     if (hasglvertexshaderarb)
00541       msgInfo << "V"; 
00542 
00543     if (hasglfragmentshaderarb)
00544       msgInfo << "F"; 
00545 
00546     if (hasglgeometryshader4arb)
00547       msgInfo << "G"; 
00548 
00549     if (hasglsampleshadingarb)
00550       msgInfo << "S"; 
00551 
00552     msgInfo << ") ";
00553   }
00554   msgInfo << sendmsg;
00555 }
00556 

Generated on Sat May 26 01:48:15 2012 for VMD (current) by doxygen1.2.14 written by Dimitri van Heesch, © 1997-2002