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

VMDApp.C

Go to the documentation of this file.
00001 /***************************************************************************
00002  *cr
00003  *cr            (C) Copyright 1995-2019 The Board of Trustees of the
00004  *cr                        University of Illinois
00005  *cr                         All Rights Reserved
00006  *cr
00007  ***************************************************************************/
00008 /***************************************************************************
00009  * RCS INFORMATION:
00010  *
00011  *      $RCSfile: VMDApp.C,v $
00012  *      $Author: johns $        $Locker:  $             $State: Exp $
00013  *      $Revision: 1.587 $      $Date: 2022/04/09 21:15:13 $
00014  *
00015  ***************************************************************************/
00016  
00017 #include <stdlib.h>
00018 #include <string.h>
00019 #include <signal.h>
00020 #include <sys/types.h>
00021 #include <sys/stat.h>
00022 #include <ctype.h> // for isalnum()
00023 
00024 #include "VMDDisplayList.h"
00025 #include "CoorPluginData.h"
00026 #include "PluginMgr.h"
00027 #include "MolFilePlugin.h"
00028 #include "Matrix4.h"
00029 #include "config.h"
00030 #include "Inform.h"
00031 #include "AtomSel.h"
00032 #include "VMDTitle.h"
00033 #include "DisplayDevice.h"
00034 #include "PickList.h"
00035 #include "PickModeList.h"
00036 #include "MaterialList.h"
00037 #include "Scene.h"
00038 #include "CommandQueue.h"
00039 #include "UIText.h"
00040 #include "Stage.h"
00041 #include "Axes.h"
00042 #include "DisplayRocker.h"
00043 #include "FPS.h"
00044 #include "MoleculeList.h"
00045 #include "Mouse.h"
00046 #include "MobileInterface.h"
00047 #include "Spaceball.h"
00048 #ifdef WIN32
00049 #include "Win32Joystick.h"
00050 #endif
00051 #include "GeometryList.h"
00052 #include "FileRenderer.h"
00053 #include "FileRenderList.h"
00054 #include "CmdAnimate.h"
00055 #include "CmdMol.h"
00056 #include "CmdMaterial.h"
00057 #include "CmdPlugin.h"
00058 #include "CmdRender.h"   // to log the render commands we execute
00059 #include "CmdTrans.h"
00060 #include "CmdDisplay.h"
00061 #include "CmdColor.h"
00062 #include "CmdLabel.h"
00063 #include "TextEvent.h"
00064 #include "CmdMenu.h"
00065 #include "P_UIVR.h"
00066 #include "P_CmdTool.h"
00067 #include "SymbolTable.h"
00068 #include "VMDCollab.h"
00069 #include "QMData.h"
00070 #include "Orbital.h"
00071 #include "QuickSurf.h"
00072 
00073 #include "CUDAAccel.h"
00074 #if defined(VMDOPENCL)
00075 #include "OpenCLUtils.h"
00076 #endif
00077 
00078 #if defined(VMDNVENC)
00079 #include "NVENCMgr.h"  // GPU-accelerated H.26[45] video encode/decode
00080 #endif
00081 #include "VideoStream.h" // GPU-accelerated H.26[45] video streaming 
00082 
00083 #if defined(VMDTHREADS) // System-specific threads code
00084 #include "WKFThreads.h"
00085 #endif
00086 
00087 #ifdef MACVMD
00088 #include "MacVMDDisplayDevice.h"
00089 #endif
00090 
00091 #ifdef VMDOPENGL        // OpenGL-specific files
00092 #if defined(VMDFLTKOPENGL)
00093 #include "FltkOpenGLDisplayDevice.h"
00094 #else
00095 #ifndef MACVMD
00096 #include "OpenGLDisplayDevice.h"
00097 #endif
00098 #endif
00099 
00100 #ifdef VMDCAVE           // CAVE-specific files
00101 #include "cave_ogl.h"
00102 #include "CaveDisplayDevice.h"
00103 #include "CaveRoutines.h"
00104 #include "CaveScene.h"
00105 #endif // VMDCAVE
00106 #endif // VMDOPENGL
00107 
00108 // OpenGL Pbuffer off-screen rendering
00109 #if defined(VMDOPENGLPBUFFER) || defined(VMDEGLPBUFFER)
00110 #include "OpenGLPbufferDisplayDevice.h"
00111 #endif
00112 
00113 #include "VMDMenu.h"
00114 #ifdef VMDFLTK           // If using FLTK GUI include FLTK objects
00115 #include "FL/forms.H"
00116 
00117 // New Fltk menus 
00118 #include "MainFltkMenu.h"
00119 #include "ColorFltkMenu.h"
00120 #include "MaterialFltkMenu.h"
00121 #include "DisplayFltkMenu.h"
00122 #include "FileChooserFltkMenu.h"
00123 #include "SaveTrajectoryFltkMenu.h"
00124 #include "GeometryFltkMenu.h"
00125 #include "GraphicsFltkMenu.h"
00126 #include "RenderFltkMenu.h"
00127 #include "ToolFltkMenu.h"
00128 
00129 #endif // VMDFLTK
00130 
00131 #ifdef VMDIMD
00132 #include "IMDMgr.h"
00133 #include "CmdIMD.h"
00134 #endif
00135 
00136 // FreeVR conflicts with the FLTK include files, so include it _after_ FLTK.
00137 #ifdef VMDFREEVR     // FreeVR-specific files
00138 #include "freevr.h"
00139 #include "FreeVRDisplayDevice.h"
00140 #include "FreeVRRoutines.h"
00141 #include "FreeVRScene.h"
00142 #endif
00143 
00144 #if defined(VMDTKCON)
00145 #include "vmdconsole.h"
00146 #endif
00147 
00148 #ifdef VMDMPI
00149 #include "VMDMPI.h" 
00150 #endif
00151 
00152 #include "vmdfsinfo.h"
00153 #include "VMDApp.h"
00154 
00155 // default atom selection
00156 #define DEFAULT_ATOMSEL "all"
00157 
00158 // XXX static data item
00159 static unsigned long repserialnum;
00160 static unsigned long texserialnum;
00161 
00162 // static initialization
00163 JString VMDApp::text_message;
00164 
00165 #if defined(VMDXPLOR)  
00166 VMDApp* VMDApp::obj = 0; 
00167 #endif
00168 
00169 VMDApp::VMDApp(int argc, char **argv, int mpion) {
00170 #if defined(VMDXPLOR)  
00171   if (!obj) obj = this; 
00172 #endif
00173 
00174   // initialize ALL member variables
00175   argc_m = argc;
00176   argv_m = (const char **)argv;
00177   mpienabled = mpion; // flag to enable/disable MPI functionality at runtime...
00178   menulist = NULL;
00179   nextMolID = 0; 
00180   stride_firsttime = 1;
00181   eofexit = 0;
00182   mouse = NULL;
00183   mobile = NULL;
00184   spaceball = NULL;
00185 #ifdef WIN32
00186   win32joystick = NULL;
00187 #endif
00188   vmdTitle = NULL; 
00189   fileRenderList = NULL;
00190   pluginMgr = NULL;
00191   uiText = NULL;
00192   uivr = NULL;
00193   uivs = NULL;
00194 #ifdef VMDIMD
00195   imdMgr = NULL;
00196 #endif
00197   display = NULL;
00198   scene = NULL;
00199   pickList = NULL;
00200   pickModeList = NULL;
00201   materialList = NULL;
00202   stage = NULL;
00203   axes = NULL;
00204   fps = NULL;
00205   commandQueue = NULL;
00206   moleculeList = NULL;
00207   geometryList = NULL;
00208   atomSelParser = NULL;
00209   anim = NULL;
00210   vmdcollab = NULL;
00211   thrpool = NULL;
00212   cuda = NULL;
00213   nvenc = NULL;
00214   strcpy(nodename, "");
00215   noderank  = 0; // init with MPI values later
00216   nodecount = 1; // init with MPI values later
00217 
00218   UpdateDisplay = TRUE;
00219   exitFlag = TRUE;
00220   ResetViewPending = FALSE;
00221 
00222   background_processing_clear();
00223 
00224   highlighted_molid  = highlighted_rep = -1;
00225 }
00226 
00227 
00228 
00229 // Permanently bind worker threads to CPUs to achieve 
00230 // peak performance and reducing run-to-run jitter for
00231 // graphics related algorithms.  This code simply performs
00232 // a one-to-one mapping of threads to CPUs at present, and
00233 // doesn't handle other cases with any greater logic yet.
00234 extern "C" void * affinitize_threads(void *voidparms) {
00235   int tid, numthreads;
00236   wkf_threadpool_worker_getid(voidparms, &tid, &numthreads);
00237   int physcpus = wkf_thread_numphysprocessors();
00238   int setthreadaffinity=1; // enable affinity assignment by default
00239 
00240   int verbose = (getenv("VMDCPUAFFINITYVERBOSE") != NULL);
00241 
00242   // XXX need to add some kind of check to skip trying to set affinity
00243   //     if the OS, batch system, or other external CPU set management
00244   //     system has already restricted or set of CPUs we can use
00245 
00246 #if defined(ARCH_SUMMIT)
00247   // XXX On the ORNL Summit system, the IBM LSF scheduler and 'jsrun'
00248   //     handle pinning of threads to CPU sockets/cores, and the application
00249   //     appears to have absolutely no control over this at present.   
00250   //     To prevent runtime errors when we try to map out and set
00251   //     the affinity of VMD CPU thread pool, we skip setting the affinity
00252   //     and live with whatever the scheduler has assigned.
00253 //  setthreadaffinity=0;
00254   if (tid == 0 && verbose) {
00255     printf("Host physcpus: %d  numthreads: %d\n", physcpus, numthreads);
00256   }
00257 #endif
00258 
00259   if ((physcpus > 0) && setthreadaffinity) {
00260     int taffinity=0;
00261  
00262 #if defined(ARCH_SUMMIT) || defined(ARCH_OPENPOWER)
00263     // debug affinity behavior on P9 w/ IBM's jsrun tool
00264     int *affinitylist=NULL;
00265     int affinitycount=0;
00266     affinitylist = wkf_cpu_affinitylist(&affinitycount);
00267 
00268     if (tid == 0 && verbose) {
00269       printf("CPU affinity count: %d\n", affinitycount);
00270       int t;
00271       for (t=0; t<affinitycount; t++) {
00272         printf("thread[0] affinity[%d]: %d\n", t, affinitylist[t]);
00273       }
00274     }
00275 
00276     if (tid < affinitycount) {
00277       setthreadaffinity=1;
00278       taffinity=affinitylist[tid];
00279 
00280       if (verbose)
00281         printf("thread[%d] affinity binding: %d\n", tid, taffinity);
00282     } else {
00283       setthreadaffinity=0;
00284       if (verbose)
00285         printf("Skipping thread[%d] affinity binding\n", tid);
00286     }
00287 #elif defined(ARCH_SUMMIT) || defined(ARCH_OPENPOWER)
00288     // on POWER8 CPU SMT "cores" are numbered consecutively, so to spread out
00289     // threads across all physical cores, threads are assigned to distinct 
00290     // physical CPU cores by multiplying thread ID * SMT depth, modulo the 
00291     // total SMT core count.
00292     if (numthreads == physcpus) {
00293       taffinity=tid * 8 % physcpus;
00294     } else {
00295 #if !defined(VMDMPI)
00296       if (tid == 0) 
00297         msgWarn << "Thread affinity binding: physical cpus != numthreads" << sendmsg;
00298 #endif
00299       taffinity=tid * 8 % physcpus;
00300     }
00301 #else
00302     // On Intel/AMD hardware, physically distinct CPU cores are numbered 
00303     // consecutively, and additional SMT "cores" appear as additional multiples
00304     // of the physical CPU core count.  It is therefore sufficient to 
00305     // use consecutive CPU indices to spread worker threads fully across CPUs
00306     // and SMT hardware threads
00307     if (numthreads == physcpus) {
00308       taffinity=tid; // set affinity of tid to same CPU id if numthreads == cpus
00309     } else {
00310 #if !defined(VMDMPI)
00311       if (tid == 0) 
00312         msgWarn << "Thread affinity binding: physical cpus != numthreads" << sendmsg;
00313 #endif
00314 
00315       taffinity=tid; // set affinity of tid to same CPU id if numthreads == cpus
00316     }
00317 #endif
00318 
00319     if (verbose)
00320       printf("Affinitizing thread[%d] to CPU[%d]...\n", tid, taffinity);
00321 
00322     wkf_thread_set_self_cpuaffinity(taffinity);
00323   }
00324 
00325   // mark CPU threads for display in profiling tools
00326   char threadname[1024];
00327   sprintf(threadname, "VMD CPU threadpool[%d]", tid);
00328   PROFILE_NAME_THREAD(threadname);
00329 
00330   return NULL;
00331 }
00332 
00333 
00334 
00335 // initialization routine for the library globals
00336 int VMDApp::VMDinit(int argc, char **argv, const char *displaytype, 
00337                     int *displayLoc, int *displaySize) {
00338   cpucaps = NULL;
00339 #if defined(VMDTHREADS)
00340   cpucaps = (wkf_cpu_caps_t *) calloc(1, sizeof(wkf_cpu_caps_t));
00341 #endif
00342 
00343   // Tell the user what we think about the hardware we're running on.
00344   // If VMD is compiled for MPI, then we don't print any of the normal
00345   // standalone startup messages and instead we use the special MPI-specific
00346   // node scan startup messages only.
00347 #if defined(VMDMPI)
00348   if (mpienabled) {
00349     vmd_mpi_nodeinfo(&noderank, &nodecount);
00350   }
00351 #endif
00352  
00353 #if defined(VMDTHREADS)
00354   int vmdnumcpus = wkf_thread_numprocessors();
00355   if (!mpienabled) {
00356     msgInfo << "Multithreading available, " << vmdnumcpus
00357             << ((vmdnumcpus > 1) ? " CPUs" : " CPU") 
00358 #if defined(VMDCPUDISPATCH)
00359             << ", ISA dispatch enabled."
00360 #else
00361             << "."
00362 #endif
00363             << sendmsg;
00364   }
00365 
00366   if (!wkf_cpu_capability_flags((wkf_cpu_caps_t *) cpucaps) &&
00367       !mpienabled) {
00368     msgInfo << "  CPU features: ";
00369 
00370 #if (defined(__i386__) || defined(__x86_64__) || defined(_M_IX86) || defined(_M_AMD64))
00371     if (cpucaps->flags & CPU_SSE2)
00372       msgInfo << "SSE2 ";
00373     if (cpucaps->flags & CPU_SSE4_1)
00374       msgInfo << "SSE4.1 ";
00375     if (cpucaps->flags & CPU_AVX)
00376       msgInfo << "AVX ";
00377     if (cpucaps->flags & CPU_AVX2)
00378       msgInfo << "AVX2 ";
00379     if (cpucaps->flags & CPU_FMA)
00380       msgInfo << "FMA ";
00381     if (cpucaps->flags & CPU_F16C)
00382       msgInfo << "F16 ";
00383 
00384     if ((cpucaps->flags & CPU_KNL) == CPU_KNL) {
00385       msgInfo << "KNL:AVX-512F+CD+ER+PF ";
00386     } else {
00387       if (cpucaps->flags & CPU_AVX512F)
00388         msgInfo << "AVX512F ";
00389       if (cpucaps->flags & CPU_AVX512CD)
00390         msgInfo << "AVX512CD ";
00391       if (cpucaps->flags & CPU_AVX512ER)
00392         msgInfo << "AVX512ER ";
00393       if (cpucaps->flags & CPU_AVX512PF)
00394         msgInfo << "AVX512PF ";
00395     }
00396 
00397     if (cpucaps->flags & CPU_HT)
00398       msgInfo << "HT ";
00399 
00400     if (cpucaps->flags & CPU_HYPERVISOR) {
00401       msgInfo << sendmsg;
00402       msgInfo << "  Detected VM or hypervisor execution environment";
00403     }
00404 #endif
00405 
00406 #if (defined(ARCH_LINUXARM64) || defined(__ARM_ARCH_ISA_A64) || defined(__ARM_NEON))
00407     if (cpucaps->flags & CPU_ARM64_FP)
00408       msgInfo << "FP ";
00409     if (cpucaps->flags & CPU_ARM64_SVE)
00410       msgInfo << "SVE ";
00411 
00412     if (cpucaps->flags & CPU_ARM64_ASIMD)
00413       msgInfo << "ASIMD ";
00414     if (cpucaps->flags & CPU_ARM64_ASIMDHP)
00415       msgInfo << "ASIMDHP ";
00416     if (cpucaps->flags & CPU_ARM64_ASIMDRDM)
00417       msgInfo << "ASIMDRDM ";
00418     if (cpucaps->flags & CPU_ARM64_ASIMDDP)
00419       msgInfo << "ASIMDDP ";
00420     if (cpucaps->flags & CPU_ARM64_ASIMDFHM)
00421       msgInfo << "ASIMDFHM ";
00422 
00423     if (cpucaps->flags & CPU_ARM64_AES)
00424       msgInfo << "AES ";
00425     if (cpucaps->flags & CPU_ARM64_CRC32)
00426       msgInfo << "CRC32 ";
00427     if (cpucaps->flags & CPU_ARM64_SHA1)
00428       msgInfo << "SHA1 ";
00429     if (cpucaps->flags & CPU_ARM64_SHA2)
00430       msgInfo << "SHA2 ";
00431     if (cpucaps->flags & CPU_ARM64_SHA3)
00432       msgInfo << "SHA3 ";
00433     if (cpucaps->flags & CPU_ARM64_SHA512)
00434       msgInfo << "SHA512 ";
00435 
00436 #if defined(VMDCPUDISPATCH) && defined(__ARM_ARCH_ISA_A64) && !defined(ARCH_MACOSXARM64)
00437     if (cpucaps->flags & CPU_ARM64_SVE) {
00438       int vs32 = arm_sve_vecsize_32bits();
00439       int vs64 = arm_sve_vecsize_64bits();
00440       if (vs32 > 0 && vs64 > 0) {
00441         msgInfo << sendmsg;
00442         msgInfo << "  ARM64 SVE vector lengths  32-bit: " 
00443                 << vs32 << ",  64-bit: " << vs64;
00444       }
00445     }
00446 #endif
00447 #endif
00448 
00449     msgInfo << sendmsg;
00450   }
00451 #endif
00452 
00453   long vmdcorefree = vmd_get_avail_physmem_mb();
00454   if (!mpienabled && vmdcorefree >= 0) {
00455     long vmdcorepcnt = vmd_get_avail_physmem_percent();
00456 
00457     // on systems with large physical memory (tens of GB) we
00458     // report gigabytes of memory rather than megabytes
00459     if (vmdcorefree > 8000) {
00460       vmdcorefree += 512; // round up to nearest GB
00461       vmdcorefree /= 1024;
00462       msgInfo << "Free system memory: " << vmdcorefree
00463               << "GB (" << vmdcorepcnt << "%)" << sendmsg;
00464     } else {
00465       msgInfo << "Free system memory: " << vmdcorefree
00466               << "MB (" << vmdcorepcnt << "%)" << sendmsg;
00467     }
00468   }
00469 
00470 #if defined(VMDTHREADS)
00471   PROFILE_PUSH_RANGE("CPU thread pool init", 3);
00472   thrpool=wkf_threadpool_create(wkf_thread_numprocessors(), WKF_THREADPOOL_DEVLIST_CPUSONLY);
00473 
00474   // affinitize persistent threadpool to the available CPUs
00475   wkf_tasktile_t tile;
00476   memset(&tile, 0, sizeof(tile));
00477   wkf_threadpool_launch((wkf_threadpool_t *) thrpool, 
00478                         affinitize_threads, NULL, 1);
00479   PROFILE_POP_RANGE();
00480 #endif
00481 
00482 #if defined(VMDCUDA)
00483   PROFILE_PUSH_RANGE("GPU device pool init", 0);
00484 
00485   // register all usable CUDA GPU accelerator devices
00486   cuda = new CUDAAccel();
00487 
00488   PROFILE_POP_RANGE();
00489 #endif
00490 
00491 #if defined(VMDMPI)
00492   if (mpienabled) {
00493     PROFILE_PUSH_RANGE("MPI init", 5);
00494 
00495     // initialize MPI node info and print output here
00496     vmd_mpi_nodescan(NULL, NULL, nodename, sizeof(nodename), 
00497                      (cuda != NULL) ? cuda->num_devices() : 0);
00498 
00499     PROFILE_POP_RANGE();
00500   }
00501 #endif
00502 
00503   // only emit detailed GPU enumeration data if we're running on a single node
00504   if (nodecount == 1) {
00505     // CUDA and OpenCL GPU/multi-core acceleration
00506 #if defined(VMDCUDA)
00507     cuda->print_cuda_devices();
00508 #endif
00509 #if defined(VMDOPENCL)
00510     vmd_cl_print_platform_info();
00511 #endif
00512   }
00513 
00514 #if defined(VMDNVENC)
00515   // It may eventually be desirable to relocate NVENC initialization after
00516   // OpenGL or Vulkan initialization has completed so that we have access 
00517   // to window handles and OpenGL or Vulkan context info at the point 
00518   // where video streaming is setup.  There don't presently appear to be
00519   // any APIs for graphics interop w/ NVENC.  We may need to instead use 
00520   // the GRID IFR library to achieve zero-copy streaming for OpenGL / Vulkan.
00521   // Direct use of NVENC seems most appropriate for ray tracing however, since
00522   // it allows CUDA interop.
00523 
00524   PROFILE_PUSH_RANGE("NVENC init", 0);
00525   nvenc = new NVENCMgr;
00526   int nvencrc;
00527   if ((nvencrc = nvenc->init()) == NVENCMGR_SUCCESS) {
00528     nvencrc = nvenc->open_session();
00529   }
00530   if (nvencrc == NVENCMGR_SUCCESS) {
00531     msgInfo << "NVENC GPU-accelerated video streaming available."
00532             << sendmsg;
00533   } else {
00534     msgInfo << "NVENC GPU-accelerated video streaming is not available." 
00535             << sendmsg;
00536   }
00537   PROFILE_POP_RANGE();
00538 #endif
00539 
00540 
00541   PROFILE_PUSH_RANGE("UIObject init", 1);
00542 
00543   //
00544   // create commandQueue before all UIObjects!
00545   //
00546   commandQueue = new CommandQueue(); 
00547 
00548 
00549   // XXX This is currently only used for 64-bit MacOS X builds using Cocoa...
00550   // XXX Francois-Xavier Coudert has noted that this code path also corrected
00551   //     startup crashes he had been having with 32-bit builds using MacOS X
00552   //     10.7.x using FLTK 1.3.0.  It remains to be seen how stable the GUI is
00553   //     for the 32-bit build when the Cocoa workaround is active.  It has not
00554   //     been very stable for 64-bit builds thus far.
00555 #if defined(ARCH_MACOSXARM64) || defined(ARCH_MACOSXX86_64)
00556   // Tcl/Tk _must_ be initialized before FLTK due to low-level implementation
00557   // details of Cocoa-based Tk and FLTK code required for 64-bit MacOS X.
00558   uiText = new UIText(this, (strcmp(displaytype, "TEXT") != 0), 0); // text user interface
00559 #endif
00560 
00561   PROFILE_POP_RANGE();
00562   PROFILE_PUSH_RANGE("DisplayDevice init", 0);
00563 
00564   // initialize the display
00565   int *dloc = (displayLoc[0]  > 0 ? displayLoc  : (int *) NULL);
00566 
00567   int dsiz[2] = { 512, 512 };
00568   if (displaySize && displaySize[0] > 0 && displaySize[1] > 0) {
00569     dsiz[0] = displaySize[0];
00570     dsiz[1] = displaySize[1];
00571   }
00572 
00573   // initialize static data items
00574   repserialnum = 0; // initialize the display list serial number
00575   texserialnum = 0; // initialize the texture list serial number
00576 
00577 #ifdef MACVMD
00578   display = new MacVMDDisplayDevice(this, dsiz);
00579 #endif
00580 
00581   // check for a standard windowed display
00582   if (!strcmp(displaytype, "WIN") || !strcmp(displaytype, "OPENGL")) {
00583 #if defined(VMDOPENGL)
00584 #if defined(VMDFLTKOPENGL)
00585     display = new FltkOpenGLDisplayDevice(argc, argv, this, dsiz, dloc);
00586 #else
00587     display = new OpenGLDisplayDevice;
00588     if (!display->init(argc, argv, this, dsiz, dloc)) {
00589       VMDexit("Unable to create OpenGL window.", 1, 7);
00590       return FALSE;
00591     } 
00592 #endif
00593 #endif
00594   }
00595 
00596 #if defined(VMDOPENGLPBUFFER) || defined(VMDEGLPBUFFER)
00597   // check for OpenGL Pbuffer off-screen rendering context
00598   if (!strcmp(displaytype, "OPENGLPBUFFER")) {
00599     display = new OpenGLPbufferDisplayDevice;
00600     if (!display->init(argc, argv, this, dsiz, dloc)) {
00601       VMDexit("Unable to create OpenGL Pbuffer context.", 1, 7);
00602       return FALSE;
00603     } 
00604   }
00605 #endif
00606 
00607 #ifdef VMDCAVE
00608   if (!strcmp(displaytype, "CAVE") || !strcmp(displaytype, "CAVEFORMS")) {
00609     // The CAVE scene is allocated from shared memory and can be 
00610     // accessed by all of the rendering processes by virtue of its
00611     // class-specific operator new.
00612     scene = new CaveScene(this);
00613     msgInfo << "Cave shared memory scene created." << sendmsg;
00614 
00615     // the CAVE display device is created in process-private memory
00616     display = new CaveDisplayDevice;
00617 
00618     // set up pointers for cave_renderer, needs to be done before forking.
00619     set_cave_pointers(scene, display);
00620 
00621     // XXX this may cure a problem with specular highlights in CAVElib
00622     // by default CAVElib messes with the OpenGL modelview matrix, this
00623     // option prevents it from doing so, which should allow specular 
00624     // highlights to look right on multiple walls, but it breaks depth cueing.
00625     // CAVESetOption(CAVE_PROJ_USEMODELVIEW, 0);
00626     CAVESetOption(CAVE_GL_SAMPLES, 8); // enable multisample antialiasing
00627     CAVEInit();                        // fork off the rendering processes
00628     CAVEDisplay(cave_renderer, 0);     // set the fctn ptr for the renderers
00629     display->renderer_process = 0;     // this proc is the master process
00630     vmd_set_cave_is_initialized();     // flag successfull CAVE init
00631 
00632     if (!display->init(argc, argv, this, NULL, NULL)) {
00633       VMDexit("Unable to create CAVE display context.", 1, 7);
00634       return FALSE;
00635     }
00636     msgInfo << "CAVE Initialized" << sendmsg;
00637   }
00638 #endif
00639 
00640 #ifdef VMDFREEVR
00641   if (!strcmp(displaytype, "FREEVR") || !strcmp(displaytype, "FREEVRFORMS")) {
00642     // The FreeVR scene is allocated from shared memory and can be 
00643     // accessed by all of the rendering processes by virtue of its
00644     // class-specific operator new.
00645     scene = new FreeVRScene(this);
00646     msgInfo << "FreeVR shared memory scene created." << sendmsg;
00647 
00648     // the FreeVR display device is created in process-private memory
00649     display = new FreeVRDisplayDevice;
00650 
00651     // set up pointers for freevr_renderer, needs to be done before forking.
00652     set_freevr_pointers(scene, display);
00653 
00654     // set the function pointer for the per-screen renderers
00655     vrFunctionSetCallback(VRFUNC_ALL_DISPLAY, vrCallbackCreate(freevr_renderer, 1, &display));  
00656     vrStart();                         // fork off the rendering processes
00657     vrSystemSetName("VMD using FreeVR display form");
00658     vrSystemSetAuthors("John Stone, Justin Gullingsrud, Bill Sherman");
00659     vrSystemSetExtraInfo(VERSION_MSG);
00660     vrInputSet2switchDescription(0, "Terminate the FreeVR windows");
00661     vrInputSet2switchDescription(1, "Interface with the Graphics->Tools grab tool");
00662     vrInputSet2switchDescription(2, "Grab the world");
00663     vrInputSet2switchDescription(3, "Reset the world's position");
00664     vrInputSetValuatorDescription(0, "Rotate us in the world about the Y-axis");
00665     vrInputSetValuatorDescription(1, "Move us though the world in the direction we point");
00666     display->renderer_process = 0;     // this proc is the master process
00667 
00668     if (!display->init(argc, argv, this, NULL, NULL)) {
00669       VMDexit("Unable to create FreeVR display context.", 1, 7);
00670       return FALSE;
00671     }
00672     msgInfo << "FreeVR Initialized" << sendmsg;
00673   }
00674 #endif
00675 
00676   // If no scene object has been created yet (e.g. CAVE/FreeVR), create one.
00677   if (!scene) {
00678     scene = new Scene;
00679   }
00680 
00681   // If a real display doesn't exist, create a stub display that eats commands
00682   if (!display) {
00683     display = new DisplayDevice("Default Display");
00684     if (!display->init(argc, argv, this, dsiz, dloc)) {
00685       VMDexit("Unable to create stub default display context.", 1, 7);
00686       return FALSE;
00687     }
00688   }
00689 
00690   // print any useful informational messages now that the display is setup
00691   if (display->get_num_processes() > 1) {
00692     msgInfo << "Started " << display->get_num_processes() 
00693             << " slave rendering processes." << sendmsg;
00694   }
00695 
00696   PROFILE_POP_RANGE();
00697 
00698   //
00699   // create other global objects for the program
00700   //
00701   PROFILE_PUSH_RANGE("Internal state init", 1);
00702 
00703   rocker = new DisplayRocker(&(scene->root));
00704 
00705   pluginMgr = new PluginMgr;
00706 
00707   atomSelParser = new SymbolTable(this);
00708   atomSelParser_init(atomSelParser);
00709 
00710   pickModeList = new PickModeList(this);
00711   pickList = new PickList(this);
00712 
00713   // create material list
00714   materialList = new MaterialList(&scene->root);
00715 
00716   // create other useful graphics objects
00717   axes = new Axes(display, &(scene->root));
00718   pickList->add_pickable(axes);
00719   
00720   fps = new FPS(display, &(scene->root));
00721   fps->off();
00722 
00723   // create the list of molecules (initially empty)
00724   moleculeList = new MoleculeList(this, scene);
00725 
00726   // create shared QuickSurf object used by all reps
00727   qsurf = new QuickSurf();
00728 
00729   anim = new Animation(this);
00730   anim->On();
00731 
00732   // create the list of geometry monitors (initially empty)
00733   geometryList = new GeometryList(this, &(scene->root));
00734 
00735   menulist = new NameList<VMDMenu *>;
00736 
00737   // If the text UI hasn't already been initialized then initialize it here.
00738   // Cocoa-based FLTK/Tk builds of VMD for 64-bit MacOS X must 
00739   // initialize Tcl/Tk first, so that FLTK works correctly.
00740   if (uiText == NULL)
00741     uiText = new UIText(this, display->supports_gui(), mpienabled); // text interface
00742   uiText->On();
00743 
00744   mouse = new Mouse(this); // mouse user interface
00745   mouse->On();
00746 
00747   mobile = new Mobile(this); // Smartphone/tablet network input device
00748   mobile->On();
00749 
00750   spaceball = new Spaceball(this); // Spaceball 6DOF input device
00751   spaceball->On();
00752 
00753 #ifdef WIN32
00754   win32joystick = new Win32Joystick(this); // Win32 Joystick devices
00755   win32joystick->On();
00756 #endif
00757 
00758 #ifdef VMDIMD
00759   imdMgr = new IMDMgr(this);
00760   imdMgr->On();
00761 #endif
00762 
00763 #if 1 || defined(VMDNVPIPE)
00764   // only create a video streaming object if we have back-end encoder support
00765   uivs = new VideoStream(this);
00766   uivs->On();
00767 #endif
00768 
00769   stage = new Stage(&(scene->root));
00770   pickList->add_pickable(stage);
00771 
00772   vmdcollab = new VMDCollab(this);
00773   vmdcollab->On();
00774 
00775   // make the classes which can render scenes to different file formats
00776   fileRenderList = new FileRenderList(this);
00777 
00778   display->queue_events(); // begin accepting UI events in graphics window
00779 
00780   // Create the menus; XXX currently this must be done _before_ calling
00781   // uiText->read_init() because otherwise the new menus created by the 
00782   // plugins loaded by the iit script won't be added to the main menu.
00783   activate_menus();
00784 
00785   PROFILE_POP_RANGE();
00786   PROFILE_PUSH_RANGE("Plugin shared obj init", 5);
00787   
00788   // XXX loading static plugins should be controlled by a startup option
00789   pluginMgr->load_static_plugins();
00790 
00791   // plugin_update must take place _after_ creation of uiText.
00792   plugin_update();
00793 
00794   PROFILE_POP_RANGE();
00795   PROFILE_PUSH_RANGE("Interp loop init", 3);
00796 
00797   VMDupdate(VMD_IGNORE_EVENTS); // flush cmd queue, prepare to enter event loop
00798 
00799   // Read the initialization code for the text interpreter.
00800   // We wait to do it now since that script might contain commands that use 
00801   // the event queue
00802   uiText->read_init();
00803 
00804   // If there's no text interpreter, show the main menu
00805 #ifndef VMDTCL
00806 #ifndef VMDPYTHON
00807   menu_show("main", 1);
00808 #endif
00809 #endif
00810 
00811 #if defined(VMDTCL)
00812   // XXX hacks for Swift/T
00813   if (mpienabled) {
00814     commandQueue->runcommand(
00815       new TclEvalEvent("parallel swift_clone_communicator"));
00816   }
00817 #endif
00818   
00819   PROFILE_POP_RANGE();
00820 
00821   // successful initialization.  Turn off the exit flag return success
00822   exitFlag = FALSE;
00823   return TRUE;
00824 }
00825 
00826 int VMDApp::num_menus() { return menulist->num(); }
00827 
00828 int VMDApp::add_menu(VMDMenu *m) {
00829   if (menulist->typecode(m->get_name()) != -1) {
00830     msgErr << "Menu " << m->get_name() << " already exists." << sendmsg;
00831     return 0;  
00832   }
00833   menulist->add_name(m->get_name(), m);
00834   return 1;
00835 }
00836  
00837 int VMDApp::remove_menu(const char *name) {
00838   int id = menulist->typecode(name);
00839   if (id == -1) {
00840     msgErr << "Menu " << name << " does not exist." << sendmsg;
00841     return 0;  
00842   }
00843   NameList<VMDMenu *> *newmenulist = new NameList<VMDMenu *>;
00844   for (int i=0; i<menulist->num(); i++) {
00845     VMDMenu *menu = menulist->data(i);
00846     if (i == id) {
00847       delete menu;
00848     } else {
00849       newmenulist->add_name(menu->get_name(), menu);
00850     }
00851   }
00852   delete menulist;
00853   menulist = newmenulist;
00854   return 1;
00855 }
00856  
00857 void VMDApp::menu_add_extension(const char *shortname, const char *menu_path) {
00858   commandQueue->runcommand(new CmdMenuExtensionAdd(shortname,menu_path));
00859 }
00860 
00861 void VMDApp::menu_remove_extension(const char *shortname) {
00862   commandQueue->runcommand(new CmdMenuExtensionRemove(shortname));
00863 }
00864 
00865 const char *VMDApp::menu_name(int i) { 
00866   return menulist->name(i); 
00867 }
00868 
00869 int VMDApp::menu_id(const char *name) {
00870   return menulist->typecode(name);
00871 }
00872 
00873 int VMDApp::menu_status(const char *name) {
00874   int id = menulist->typecode(name);
00875   if (id == -1) return 0;
00876   return menulist->data(id)->active();
00877 }
00878 
00879 int VMDApp::menu_location(const char *name, int &x, int &y) {
00880   int id = menulist->typecode(name);
00881   if (id == -1) return 0;
00882   menulist->data(id)->where(x, y);
00883   return 1;
00884 }
00885 
00886 int VMDApp::menu_show(const char *name, int on) {
00887   int id = menulist->typecode(name);
00888   if (id == -1) return 0;
00889   VMDMenu *obj = menulist->data(name);
00890   if (on)
00891     obj->On();
00892   else
00893     obj->Off();
00894   commandQueue->runcommand(new CmdMenuShow(name, on));
00895   return 1;
00896 }
00897 
00898 int VMDApp::menu_move(const char *name, int x, int y) {
00899   int id = menulist->typecode(name);
00900   if (id == -1) return 0;
00901   menulist->data(id)->move(x, y);
00902   return 1;
00903 }
00904 
00905 
00906 int VMDApp::menu_select_mol(const char *name, int molno) {
00907   int id = menulist->typecode(name);
00908   if (id == -1) return 0;
00909   return menulist->data(id)->selectmol(molno);
00910 }
00911 
00912 
00913 // redraw the screen and update all things that need updating
00914 int VMDApp::VMDupdate(int check_for_events) {
00915   PROFILE_PUSH_RANGE("VMDApp::VMDupdate()", 5);
00916 
00917   // clear background processing flag
00918   background_processing_clear();
00919 
00920   // see if there are any pending events; if so, get them
00921   if (check_for_events) {
00922     commandQueue->check_events();
00923 #ifdef VMDGUI
00924 #ifdef VMDFLTK
00925     // if we are using the FLTK library ...
00926     if (display->supports_gui()) {
00927 #if defined(ARCH_MACOSX) && defined(VMDTCL)
00928       // don't call wait(0) since this causes Tcl/Tk to mishandle events
00929       Fl::flush();
00930 #elif (defined(ARCH_MACOSXARM64) || defined(ARCH_MACOSXX86) || defined(ARCH_MACOSXX86_64)) && defined(VMDTCL)
00931       // starting with more recent revs of FLTK and Tcl/Tk, we should no
00932       // longer need to drop events
00933       Fl::wait(0);
00934 #else
00935       Fl::wait(0);
00936 #endif
00937     }
00938 #endif
00939 #endif
00940   } 
00941   
00942   // check if the user has requested to exit the program.
00943   if (exitFlag) {
00944     PROFILE_POP_RANGE();
00945     return FALSE;
00946   }
00947  
00948   commandQueue->execute_all(); // execute commands still in the queue
00949 
00950   //
00951   // if video streaming is active and we're a client with an active
00952   // connection, all local rendering is disabled..
00953   //
00954   if (uivs == NULL || !uivs->cli_connected()) {
00955     int needupdate = 0;
00956 #if 1
00957     // Only prepare objects if display update is enabled
00958     // XXX avoid N^2 behavior when loading thousdands of molecules, 
00959     // don't prepare for drawing unless we have to.
00960     if (UpdateDisplay) {
00961       // If a resetview is pending, take care of it now before drawing
00962       if (ResetViewPending) 
00963         scene_resetview_newmoldata();
00964 
00965       needupdate = scene->prepare(); // prepare all objects for drawing
00966     } else {
00967       // XXX this has to be done currently to force trajectories to continue
00968       //     loading frames since they don't have their own UIObject yet.
00969       int molnum = moleculeList->num();
00970       int i;
00971       for (i=0; i<molnum; i++) {
00972         Molecule *mol = moleculeList->molecule(i);
00973         if (mol != NULL) {
00974           if (mol->get_new_frames()) {
00975             needupdate = 1; // need to update if any new frames were loaded
00976           }
00977         }
00978       }
00979     }
00980 #else
00981     // XXX this has to be done currently to force trajectories to continue
00982     //     loading frames since they don't have their own UIObject yet.
00983     needupdate = scene->prepare(); // prepare all objects for drawing
00984 #endif
00985 
00986     // turn off the spinning vmd when molecules are loaded
00987     if (vmdTitle && moleculeList->num() > 0) {
00988       delete vmdTitle;
00989       vmdTitle = NULL;
00990     }
00991   
00992     // Update the display (or sleep a tiny bit).
00993     if (UpdateDisplay && (needupdate || display->needRedraw())) {
00994       scene->draw(display);   // make the display redraw if necessary
00995       scene->draw_finished(); // perform any necessary post-drawing cleanup
00996 
00997       // if video streaming is active, we tell the encoder a new frame is ready
00998       if (uivs != NULL && uivs->srv_connected()) {
00999 #if 0
01000         int xs, ys;
01001         unsigned char *img = display->readpixels_rgba4u(xs, ys);
01002         if (img != NULL) {
01003           uivs->srv_send_frame(img, xs * 4, xs, ys, 0);
01004           free(img);
01005         }
01006 #elif 0
01007         uivs->video_frame_pending();
01008 #endif
01009       }
01010     } else {
01011       // if not updating the display or doing background I/O, 
01012       // we sleep so we don't hog CPU.
01013       if (!needupdate && !background_processing())
01014         vmd_msleep(1); // sleep for 1 millisecond or more
01015     }
01016   } // no active video-streaming-client connection
01017 
01018   // XXX A hack to decrease CPU utilization on machines that have
01019   //     problems keeping up with the 3-D draw rate at full speed.
01020   if (getenv("VMDMSECDELAYHACK") != NULL) {
01021     // Delay the whole program for a user-specified number of milliseconds.  
01022     vmd_msleep(atoi(getenv("VMDMSECDELAYHACK"))); 
01023   }
01024 
01025   PROFILE_POP_RANGE();
01026   return TRUE;
01027 }
01028 
01029 
01030 // exit the program normally; first delete all the necessary objects
01031 void VMDApp::VMDexit(const char *exitmsg, int exitcode, int pauseseconds) {
01032 
01033 #if defined(VMDTKCON)
01034   // switch to text mode and flush all pending messages to the screen.
01035   vmdcon_use_text((void *)uiText->get_tcl_interp());
01036   vmdcon_purge();
01037 #endif
01038 
01039 #if defined(VMDMPI)
01040   // If MPI parallel execution is in effect, help console output complete before
01041   // final shutdown.
01042   if (mpienabled) { 
01043     fflush(stdout);
01044     vmd_mpi_barrier(); // wait for peers before printing final messages
01045     if (noderank == 0)
01046       vmd_msleep(250); // give peer output time to percolate to the console...
01047   }
01048 #endif
01049 
01050   // only print exit status output on the first exit call
01051   if (exitFlag == 0 || (exitmsg != NULL && strlen(exitmsg))) {
01052     msgInfo << VERSION_MSG << sendmsg; 
01053     if (exitmsg && strlen(exitmsg)) {
01054       msgInfo << exitmsg << sendmsg;
01055     } else {
01056       msgInfo << "Exiting normally." << sendmsg;
01057     }
01058   }
01059 
01060   vmd_sleep(pauseseconds);  // sleep for requested number of seconds
01061 
01062   // make the VMDupdate event loop return FALSE.
01063   exitFlag = 1;
01064 }
01065 
01066 VMDApp::~VMDApp() {
01067   int i;
01068 
01069   // delete shared QuickSurf object used by all reps.
01070   // destroy QuickSurf object prior to other GPU-related teardown
01071   if (qsurf)          delete qsurf;
01072 
01073   // delete all objects we created during initialization
01074   if (fileRenderList) delete fileRenderList;
01075   if (mouse)          delete mouse;
01076   if (mobile)         delete mobile;
01077   if (spaceball)      delete spaceball;
01078 
01079 #ifdef WIN32
01080   if (win32joystick)  delete win32joystick;
01081 #endif
01082 
01083   if (uivr)           delete uivr;
01084 
01085   if (uivs)           delete uivs;
01086   uivs = NULL;        // prevent free mem accesses in event loops
01087 
01088   if (geometryList)   delete geometryList;
01089 
01090 #ifdef VMDIMD
01091   if (imdMgr)         delete imdMgr;
01092   imdMgr = NULL;      // prevent free mem reads at moleculeList deletion
01093 #endif
01094 
01095   if (vmdTitle)       delete vmdTitle;
01096   if (stage)          delete stage;
01097   if (axes)           delete axes;
01098   if (fps)            delete fps;
01099   if (pickModeList)   delete pickModeList;
01100   if (materialList)   delete materialList;
01101   if (pluginMgr)      delete pluginMgr;
01102   if (cuda)           delete cuda;
01103   delete vmdcollab;
01104 
01105   // delete all of the Forms;
01106   if (menulist) {
01107     for (i=0; i<menulist->num(); i++)
01108       delete menulist->data(i);
01109     delete menulist;
01110   }
01111 
01112 #ifdef VMDGUI
01113   // Close all GUI windows
01114 #ifdef VMDFLTK
01115   if (display->supports_gui()) {
01116     Fl::wait(0); // Give Fltk a chance to close the menu windows.  
01117   }
01118 #endif
01119 #endif
01120 
01121   // Tcl/Python interpreters can only be deleted after Tk forms are shutdown
01122   if (uiText)         delete uiText;
01123 
01124   // delete the list of user keys and descriptions 
01125   for (i=0; i<userKeys.num(); i++)
01126     delete [] userKeys.data(i);
01127 
01128   for (i=0; i<userKeyDesc.num(); i++)
01129     delete [] userKeyDesc.data(i);
01130 
01131   delete atomSelParser;
01132   delete anim;
01133 
01134   // delete commandQueue _after_ all UIObjects have been deleted; otherwise
01135   // they will try to unRegister with a deleted CommandQueue.
01136   delete commandQueue;
01137 
01138   // (these dependencies really suck) delete moleculelist after uiText
01139   // because text interfaces might use commands that require moleculeList to
01140   // be there.
01141   delete moleculeList;
01142 
01143   // picklist can't be deleted until the molecule is deleted, since
01144   // the DrawMolecule destructor needs it.
01145   delete pickList;
01146  
01147   delete display;
01148   delete scene;
01149 
01150 #if defined(VMDTHREADS)
01151   if (thrpool) {
01152     wkf_threadpool_destroy((wkf_threadpool_t *) thrpool);
01153     thrpool=NULL;
01154   }
01155 #endif
01156 
01157   if (cpucaps) {
01158     free(cpucaps);
01159   }
01160 }
01161 
01162 unsigned long VMDApp::get_repserialnum(void) {
01163   // first serial number returned will be 1, never return 0.
01164   repserialnum++;
01165   return repserialnum;
01166 }
01167 
01168 unsigned long VMDApp::get_texserialnum(void) {
01169   // first serial number returned will be 1, never return 0.
01170   texserialnum++;
01171   return texserialnum;
01172 }
01173 
01174 void VMDApp::show_stride_message() {
01175   if (stride_firsttime) {
01176     stride_firsttime = 0;
01177     msgInfo <<
01178      "In any publication of scientific results based in part or\n"
01179      "completely on the use of the program STRIDE, please reference:\n"
01180      " Frishman,D & Argos,P. (1995) Knowledge-based secondary structure\n"
01181      " assignment. Proteins: structure, function and genetics, 23, 566-579." 
01182       << "\n" << sendmsg;
01183   }
01184 }
01185 
01186 // this is a nasty hack until we get around to returning values from scripts
01187 // properly.
01188 
01189 #ifdef VMDTK
01190 #include <tcl.h> 
01191 #endif
01192 
01193 char *VMDApp::vmd_choose_file(const char *title,
01194         const char *extension, 
01195         const char *extension_label, int do_save) {
01196   
01197  char *chooser = getenv("VMDFILECHOOSER");
01198  if (!chooser || !strupcmp(chooser, "TK")) {
01199     
01200 #ifdef VMDTK
01201   JString t = title;
01202   JString ext = extension;
01203   JString label = extension_label;
01204   char *cmd = new char[300 + t.length() +ext.length() + label.length()];
01205   // no default extension for for saves/loads , because otherwise it 
01206   // automatically adds the file extension whether you specify it or not, and 
01207   // when the extension is * it won't let you save/load a file without an 
01208   // extension!
01209   if (do_save) {
01210     sprintf(cmd, "tk_getSaveFile -title {%s} -filetypes {{{%s} {%s}} {{All files} {*}}}", (const char *)t, (const char *)extension_label, (const char *)extension);
01211   } else {
01212     sprintf(cmd, "tk_getOpenFile -title {%s} -filetypes {{{%s} {%s}} {{All files} {*}}}", (const char *)t, (const char *)extension_label, (const char *)extension);
01213   }
01214   Tcl_Interp *interp = uiText->get_tcl_interp();
01215   if (interp) {
01216     int retval = Tcl_Eval(interp, cmd);
01217     delete [] cmd;
01218     if (retval == TCL_OK) {
01219       const char *result = Tcl_GetStringResult(interp);
01220       if (result == NULL || strlen(result) == 0) {
01221         return NULL;
01222       } else {
01223         return stringdup(result);
01224       }
01225     }
01226   }
01227   // fall through to next level on failure
01228 #endif
01229 
01230  } 
01231 
01232 #ifdef VMDFLTK
01233   return stringdup(fl_file_chooser(title, extension, NULL));
01234 #endif
01235 
01236   char *result = new char[1024];
01237   if (fgets(result, 1024, stdin) == NULL)
01238     result[0] = '\0';
01239 
01240   return result;
01241 }
01242  
01243 // file renderer API
01244 int VMDApp::filerender_num() {
01245   return fileRenderList->num();
01246 }
01247 const char *VMDApp::filerender_name(int n) {
01248   return fileRenderList->name(n);
01249 }
01250 const char *VMDApp::filerender_prettyname(int n) {
01251   return fileRenderList->pretty_name(n);
01252 }
01253 int VMDApp::filerender_valid(const char *method) {
01254   return (fileRenderList->find(method) != NULL);
01255 }
01256 // Find short renderer name from the "pretty" GUI renderer name
01257 const char *VMDApp::filerender_shortname_from_prettyname(const char *pretty) {
01258   return fileRenderList->find_short_name_from_pretty_name(pretty);
01259 }
01260 int VMDApp::filerender_has_antialiasing(const char *method) {
01261   return (fileRenderList->has_antialiasing(method));
01262 }
01263 int VMDApp::filerender_aasamples(const char *method, int aasamples) {
01264   return fileRenderList->aasamples(method, aasamples);
01265 }
01266 int VMDApp::filerender_aosamples(const char *method, int aosamples) {
01267   return fileRenderList->aosamples(method, aosamples);
01268 }
01269 int VMDApp::filerender_imagesize(const char *method, int *w, int *h) {
01270   if (!w || !h) return FALSE;
01271   return fileRenderList->imagesize(method, w, h); 
01272 }
01273 int VMDApp::filerender_has_imagesize(const char *method) {
01274   return fileRenderList->has_imagesize(method);
01275 }
01276 int VMDApp::filerender_aspectratio(const char *method, float *aspect) {
01277   if (!aspect) return FALSE;
01278   return fileRenderList->aspectratio(method, aspect);
01279 }
01280 int VMDApp::filerender_numformats(const char *method) {
01281   return fileRenderList->numformats(method);
01282 }
01283 const char *VMDApp::filerender_get_format(const char *method, int i) {
01284   return fileRenderList->format(method, i);
01285 }
01286 const char *VMDApp::filerender_cur_format(const char *method) {
01287   return fileRenderList->format(method);
01288 }
01289 int VMDApp::filerender_set_format(const char *m, const char *fmt) {
01290   return fileRenderList->set_format(m, fmt);
01291 }
01292 
01293 int VMDApp::filerender_render(const char *m, const char *f, const char *e) {
01294   int retval = fileRenderList->render(f, m, e);
01295   if (retval) {
01296     commandQueue->runcommand(new CmdRender(f, m, e));
01297   }
01298   return retval;
01299 }
01300 const char *VMDApp::filerender_option(const char *m, const char *o) {
01301   FileRenderer *ren = fileRenderList->find(m);
01302   if (!ren) {
01303     return NULL;
01304   }
01305   if (o) {
01306     ren->set_exec_string(o);
01307     commandQueue->runcommand(new CmdRenderOption(m, o));
01308   }
01309   return ren->saved_exec_string();
01310 }
01311 
01312 // XXX The Scene doesn't return error codes, so I don't know if the commands
01313 // worked or not.  I do what error checking I can here and hope that it works.
01314 int VMDApp::scene_rotate_by(float angle, char ax, float incr) {
01315   if (uivs && uivs->cli_connected()) {
01316     uivs->cli_send_rotate_by(angle, ax);
01317     return TRUE;
01318   }
01319 
01320   if (ax < 'x' || ax > 'z') return FALSE;  // failed
01321   rocker->stop_rocking();
01322   if (incr) {
01323     int nsteps = (int)(fabs(angle / incr) + 0.5);
01324     incr = (float) (angle < 0.0f ? -fabs(incr) : fabs(incr));
01325     rocker->start_rocking(incr, ax, nsteps, TRUE);
01326     commandQueue->runcommand(new CmdRotate(angle, ax, CmdRotate::BY, incr)); 
01327   } else {
01328     scene->root.add_rot(angle, ax);
01329     commandQueue->runcommand(new CmdRotate(angle, ax, CmdRotate::BY));
01330   }
01331   return TRUE;
01332 }
01333 int VMDApp::scene_rotate_to(float angle, char ax) {
01334   if (ax < 'x' || ax > 'z') return FALSE;  // failed
01335   rocker->stop_rocking();
01336   scene->root.set_rot(angle, ax);
01337   commandQueue->runcommand(new CmdRotate(angle, ax, CmdRotate::TO));
01338   return TRUE;
01339 }
01340 int VMDApp::scene_rotate_by(const float *m) {
01341   Matrix4 mat(m);
01342   scene->root.add_rot(mat);
01343   commandQueue->runcommand(new CmdRotMat(mat, CmdRotMat::BY));
01344   return TRUE;
01345 }
01346 int VMDApp::scene_rotate_to(const float *m) {
01347   Matrix4 mat(m);
01348   scene->root.set_rot(mat);
01349   commandQueue->runcommand(new CmdRotMat(mat, CmdRotMat::TO));
01350   return TRUE;
01351 }
01352 int VMDApp::scene_translate_by(float x, float y, float z) {
01353   if (uivs && uivs->cli_connected()) {
01354     uivs->cli_send_translate_by(x, y, z);
01355     return TRUE;
01356   }
01357 
01358   scene->root.add_glob_trans(x, y, z);
01359   commandQueue->runcommand(new CmdTranslate(x,y,z,CmdTranslate::BY));
01360   return TRUE;
01361 }
01362 int VMDApp::scene_translate_to(float x, float y, float z) {
01363   scene->root.set_glob_trans(x, y, z);
01364   commandQueue->runcommand(new CmdTranslate(x,y,z,CmdTranslate::TO));
01365   return TRUE;
01366 }
01367 int VMDApp::scene_scale_by(float s) {
01368   if (uivs && uivs->cli_connected()) {
01369     uivs->cli_send_scale_by(s);
01370     return TRUE;
01371   }
01372 
01373   if (s <= 0) return FALSE; 
01374   scene->root.mult_scale(s);
01375   commandQueue->runcommand(new CmdScale(s, CmdScale::BY));
01376   return TRUE;
01377 }
01378 int VMDApp::scene_scale_to(float s) {
01379   if (s <= 0) return FALSE; 
01380   scene->root.set_scale(s);
01381   commandQueue->runcommand(new CmdScale(s, CmdScale::TO));
01382   return TRUE;
01383 }
01384 void VMDApp::scene_resetview_newmoldata() {
01385 #if 1
01386   // XXX avoid N^2 behavior when loading thousands of molecules
01387   // we should only be resetting the view when necessary
01388   if (UpdateDisplay) {
01389     int nodisrupt = 0;
01390 
01391     if (getenv("VMDNODISRUPTHACK"))
01392       nodisrupt=1;
01393 
01394     if (nodisrupt && (moleculeList->num() > 1)) {
01395       moleculeList->center_top_molecule(); // new/top mol inherits current view
01396     } else {
01397       scene_resetview(); // reset all molecules to the newly loaded structure
01398     }
01399     ResetViewPending = FALSE;
01400   } else {
01401     ResetViewPending = TRUE;
01402   }
01403 #else
01404   scene_resetview(); // reset all molecules to the newly loaded structure
01405 #endif
01406 }
01407 void VMDApp::scene_resetview() {
01408   scene->root.reset_transformation();
01409   // center the view based on the displayed representations
01410   moleculeList->center_from_top_molecule_reps();
01411   moleculeList->center_all_molecules();
01412   commandQueue->runcommand(new CmdResetView);
01413 }
01414 int VMDApp::scene_rock(char ax, float step, int nsteps) {
01415   if (ax < 'x' || ax > 'z') return FALSE;  // failed
01416   rocker->start_rocking(step, ax, nsteps);
01417   commandQueue->runcommand(new CmdRockOn(step, ax, nsteps));
01418   return TRUE;
01419 }
01420 int VMDApp::scene_rockoff() {
01421   rocker->stop_rocking();
01422   commandQueue->runcommand(new CmdRockOff);
01423   return TRUE;
01424 } 
01425 int VMDApp::scene_stoprotation() {
01426   rocker->stop_rocking();
01427   mouse->stop_rotation();
01428   return TRUE;
01429 }
01430 
01431 int VMDApp::animation_num_dirs() {
01432   return Animation::ANIM_TOTAL_DIRS;
01433 }
01434 
01435 const char *VMDApp::animation_dir_name(int i) {
01436   if (i < 0 || i >= Animation::ANIM_TOTAL_DIRS) return NULL;
01437   return animationDirName[i]; 
01438 }
01439    
01440 int VMDApp::animation_set_dir(int d) {
01441   Animation::AnimDir dir = (Animation::AnimDir)d;
01442   anim->anim_dir(dir);
01443   commandQueue->runcommand(new CmdAnimDir(dir));
01444   return 1;
01445 }
01446 
01447 int VMDApp::animation_num_styles() {
01448   return Animation::ANIM_TOTAL_STYLES;
01449 }
01450 
01451 const char *VMDApp::animation_style_name(int i) {
01452   if (i < 0 || i >= Animation::ANIM_TOTAL_STYLES) return NULL;
01453   return animationStyleName[i];
01454 }
01455 
01456 int VMDApp::animation_set_style(int s) {
01457   Animation::AnimStyle style = (Animation::AnimStyle)s;
01458   anim->anim_style(style);
01459   commandQueue->runcommand(new CmdAnimStyle(style));
01460   return 1;
01461 }
01462 
01463 int VMDApp::animation_set_frame(int frame) {
01464     anim->goto_frame(frame);
01465     anim->anim_dir(Animation::ANIM_PAUSE);
01466     commandQueue->runcommand(new CmdAnimJump(frame));
01467     return 1;
01468 }
01469 
01470 int VMDApp::animation_set_stride(int stride) {
01471     anim->skip(stride);
01472     commandQueue->runcommand(new CmdAnimSkip(stride));
01473     return 1;
01474 }
01475 
01476 int VMDApp::animation_set_speed(float speed) {
01477     anim->speed(speed);
01478     commandQueue->runcommand(new CmdAnimSpeed(speed));
01479     return 1;
01480 }
01481 
01482 const char *VMDApp::filerender_default_option(const char *m) {
01483   FileRenderer *ren = fileRenderList->find(m);
01484   if (!ren) {
01485     return NULL;
01486   }
01487   return ren->default_exec_string();
01488 }
01489 const char *VMDApp::filerender_default_filename(const char *m) {
01490   FileRenderer *ren = fileRenderList->find(m);
01491   if (!ren) {
01492     return NULL;
01493   }
01494   return ren->default_filename();
01495 }
01496  
01497 
01498 // plugin stuff 
01499 
01500 vmdplugin_t *VMDApp::get_plugin(const char *type, const char *name) {
01501   if (!pluginMgr) return NULL;
01502   if (!type || !name) return NULL;
01503   PluginList p;
01504   vmdplugin_t *plugin = NULL;
01505   if (pluginMgr->plugins(p, type, name)) {
01506     plugin = p[0];
01507 
01508     // loop over plugins and select the highest version number for a 
01509     // given plugin type/name combo.
01510     for (int i=1; i<p.num(); i++) {
01511       vmdplugin_t *curplugin = p[i];
01512       if (curplugin->majorv > plugin->majorv || 
01513           (curplugin->majorv == plugin->majorv && curplugin->minorv > plugin->minorv))
01514         plugin = curplugin;
01515     }
01516   } 
01517   return plugin;
01518 }
01519 
01520 int VMDApp::list_plugins(PluginList &p, const char *type) {
01521   if (!pluginMgr) return 0;
01522   return pluginMgr->plugins(p, type);
01523 }
01524 
01525 int VMDApp::plugin_dlopen(const char *filename) {
01526   if (!pluginMgr) {
01527     msgErr << "scan_plugins: no plugin manager available" << sendmsg;
01528     return -1;
01529   }
01530   if (!filename) return -1;
01531   return pluginMgr->load_sharedlibrary_plugins(filename);
01532 }
01533 
01534 void VMDApp::plugin_update() {
01535   commandQueue->runcommand(new CmdPluginUpdate);
01536 }
01537 
01538 void VMDApp::display_update_on(int ison) {
01539   UpdateDisplay = ison;
01540 }
01541 
01542 int VMDApp::display_update_status() {
01543   return (UpdateDisplay != 0);
01544 }
01545 
01546 void VMDApp::display_update() {
01547   int prevUpdateFlag = UpdateDisplay;
01548   UpdateDisplay = 1;
01549   VMDupdate(VMD_IGNORE_EVENTS);
01550   UpdateDisplay = prevUpdateFlag;
01551 }
01552 
01553 void VMDApp::display_update_ui() {
01554   VMDupdate(VMD_CHECK_EVENTS);
01555 }
01556 
01557 int VMDApp::num_color_categories() {
01558   return scene->num_categories();
01559 }
01560 const char *VMDApp::color_category(int n) {
01561   return scene->category_name(n);
01562 }
01563 
01564 int VMDApp::color_add_item(const char *cat, const char *name, const char *defcolor) {
01565   int init_color = scene->color_index(defcolor);
01566   if (init_color < 0) {
01567     msgErr << "Cannot add color item: invalid color name '" << defcolor << "'" << sendmsg;
01568     return FALSE;
01569   }
01570   int ind = scene->category_index(cat);
01571   if (ind < 0) {
01572     ind = scene->add_color_category(cat);
01573   }
01574   if (scene->add_color_item(ind, name, init_color) < 0) {
01575     return FALSE;
01576   }
01577   commandQueue->runcommand(new CmdColorItem(cat, name, defcolor));
01578   return TRUE;
01579 }
01580 
01581 int VMDApp::num_color_category_items(const char *category) {
01582   int colCatIndex = scene->category_index(category);
01583   if (colCatIndex < 0) return 0;
01584   return scene->num_category_items(colCatIndex);
01585 }
01586 const char *VMDApp::color_category_item(const char *category, int n) {
01587   int colCatIndex = scene->category_index(category);
01588   if (colCatIndex < 0) return 0;
01589   return scene->category_item_name(colCatIndex, n); // XXX check valid n
01590 }
01591 int VMDApp::num_colors() {
01592   return MAXCOLORS;
01593 }
01594 int VMDApp::num_regular_colors() {
01595   return REGCLRS;
01596 }
01597 const char *VMDApp::color_name(int n) {
01598   return scene->color_name(n);
01599 }
01600 int VMDApp::color_index(const char *color) {
01601   if (!color) return -1;
01602   // If it's a number in the valid range, return the number; otherwise return
01603   // -1.
01604   int i;
01605   if (sscanf(color, "%d", &i)) {
01606     if (i >= 0 && i < MAXCOLORS)
01607       return i;
01608     else
01609       return -1;
01610   }
01611   // look up the color by name.
01612   return scene->color_index(color);
01613 } 
01614 int VMDApp::color_value(const char *colorname, float *r, float *g, float *b) {
01615   int colIndex = color_index(colorname);
01616   if (colIndex < 0) return 0;
01617   const float *col = scene->color_value(colIndex);
01618   *r = col[0];
01619   *g = col[1];
01620   *b = col[2];
01621   return 1;
01622 }
01623 int VMDApp::color_default_value(const char *colorname, float *r, float *g, float *b) {
01624   int colIndex = color_index(colorname);
01625   if (colIndex < 0) return 0;
01626   const float *col = scene->color_default_value(colIndex);
01627   *r = col[0];
01628   *g = col[1];
01629   *b = col[2];
01630   return 1;
01631 }
01632 const char *VMDApp::color_mapping(const char *category, const char *item) {
01633   
01634   int colCatIndex = scene->category_index(category);
01635   if (colCatIndex < 0) return 0;
01636 
01637   int colNameIndex = scene->category_item_index(colCatIndex, item);
01638   if (colNameIndex < 0) return 0;
01639   
01640   int ind = scene->category_item_value(colCatIndex, colNameIndex);
01641   return scene->color_name(ind);
01642 }
01643 
01644 const char *VMDApp::color_get_restype(const char *resname) {
01645   int id = moleculeList->resTypes.typecode(resname);
01646   if (id < 0) return NULL;
01647   return moleculeList->resTypes.data(id);
01648 }
01649 
01650 int VMDApp::color_set_restype(const char *resname, const char *restype) {
01651   int cat = moleculeList->colorCatIndex[MLCAT_RESTYPES];
01652   int ind = scene->category_item_index(cat, restype);
01653   if (ind < 0) return FALSE;  // nonexistent restype category
01654 
01655   // Use the string stored in Scene rather than the one passed to this
01656   // function, since then we don't have to worry about copying it and
01657   // freeing it later.
01658   const char *stable_restype_name = scene->category_item_name(cat, ind);
01659 
01660   // if the resname doesn't have an entry yet, create one.
01661   int resname_id = moleculeList->resTypes.add_name(resname, restype);
01662   moleculeList->resTypes.set_data(resname_id, stable_restype_name);
01663   scene->root.color_changed(cat);
01664   return TRUE;
01665 }
01666 
01667 int VMDApp::colorscale_params(float *mid, float *min, float *max, 
01668                               int *rev, int *posterize) {
01669   scene->colorscale_params(mid, min, max, rev, posterize);
01670   return 1;
01671 }
01672 int VMDApp::num_colorscale_methods() {
01673   return scene->num_colorscale_methods();
01674 }
01675 int VMDApp::colorscale_method_current() {
01676   return scene->colorscale_method();
01677 }
01678 const char *VMDApp::colorscale_method_name(int n) {
01679   if (n < 0 || n >= scene->num_colorscale_methods()) return NULL;
01680   return scene->colorscale_method_name(n);
01681 }
01682 const char *VMDApp::colorscale_method_menuname(int n) {
01683   if (n < 0 || n >= scene->num_colorscale_methods()) return NULL;
01684   return scene->colorscale_method_menuname(n);
01685 }
01686 int VMDApp::colorscale_method_index(const char *method) {
01687   for (int i=0; i<scene->num_colorscale_methods(); i++) {
01688     if (!strupncmp(method, scene->colorscale_method_name(i),CMDLEN)) {
01689       return i;
01690     }
01691   }
01692   return -1;
01693 }  
01694 
01695 int VMDApp::get_colorscale_colors(int whichScale, 
01696       float min[3], float mid[3], float max[3]) {
01697   return scene->get_colorscale_colors(whichScale, min, mid, max);
01698 }
01699 
01700 int VMDApp::set_colorscale_colors(int whichScale, 
01701       const float min[3], const float mid[3], const float max[3]) {
01702   if (scene->set_colorscale_colors(whichScale, min, mid, max)) {
01703     commandQueue->runcommand(new CmdColorScaleColors(
01704           scene->colorscale_method_name(whichScale), mid, min, max));
01705     return TRUE;
01706   }
01707   return FALSE;
01708 }
01709 
01710 
01711 int VMDApp::color_change_name(const char *category, const char *colorname, 
01712                               const char *color) {
01713 
01714   if (!category || !colorname || !color) return 0;
01715 
01716   int colCatIndex = scene->category_index(category);
01717   if (colCatIndex < 0) return 0;
01718   
01719   int colNameIndex = scene->category_item_index(colCatIndex, colorname);
01720   if (colNameIndex < 0) return 0;
01721 
01722   int newIndex = color_index(color);
01723   if (newIndex < 0) return 0;
01724  
01725   // all systems go...
01726   scene->set_category_item(colCatIndex, colNameIndex, newIndex);
01727   
01728   // tell the rest of the world
01729   commandQueue->runcommand(new CmdColorName(category, colorname, color));
01730   return 1;
01731 }
01732 
01733 
01734 int VMDApp::color_change_namelist(int numcols, char **category, 
01735                                   char **colorname, char **color) {
01736   if (numcols < 1 || !category || !colorname || !color) return 0;
01737 
01738   int i;
01739   for (i=0; i<numcols; i++) {
01740     int colCatIndex = scene->category_index(category[i]);
01741     if (colCatIndex < 0) return 0;
01742   
01743     int colNameIndex = scene->category_item_index(colCatIndex, colorname[i]);
01744     if (colNameIndex < 0) return 0;
01745 
01746     int newIndex = color_index(color[i]);
01747     if (newIndex < 0) return 0;
01748  
01749     // all systems go...
01750     scene->set_category_item(colCatIndex, colNameIndex, newIndex);
01751   }
01752  
01753   // XXX need a new command for this 
01754   // commandQueue->runcommand(new CmdColorName(category, colorname, color));
01755   return 1;
01756 }
01757 
01758 
01759 
01760 int VMDApp::color_get_from_name(const char *category, const char *colorname, 
01761                      const char **color) {
01762 
01763   if (!category || !colorname) return 0;
01764 
01765   int colCatIndex = scene->category_index(category);
01766   if (colCatIndex < 0) return 0;
01767   
01768   int colNameIndex = scene->category_item_index(colCatIndex, colorname);
01769   if (colNameIndex < 0) return 0;
01770  
01771   // all systems go...
01772   int colIndex = scene->get_category_item(colCatIndex, colNameIndex);
01773   if (colIndex < 0) return 0;
01774   
01775   *color = color_name(colIndex);
01776       
01777   return 1;
01778 }
01779 
01780 
01781 int VMDApp::color_change_rgb(const char *color, float r, float g, float b) {
01782   int ind = color_index(color);
01783   if (ind < 0) return 0;
01784   float rgb[3] = {r, g, b};
01785   scene->set_color_value(ind, rgb);
01786   commandQueue->runcommand(new CmdColorChange(color, r, g, b));
01787   return 1;
01788 }
01789 
01790 
01791 int VMDApp::color_change_rgblist(int numcols, const char **colors, float *rgb3fv) {
01792   if (numcols < 1) return 0;
01793 
01794   int i;
01795   for (i=0; i<numcols; i++) {
01796     int ind = color_index(colors[i]);
01797     if (ind < 0) return 0;
01798     scene->set_color_value(ind, &rgb3fv[i*3]);
01799   }
01800 
01801   // XXX need a new command for this
01802   // commandQueue->runcommand(new CmdColorChange(color, r, g, b));
01803   return 1;
01804 }
01805   
01806   
01807 int VMDApp::colorscale_setparams(float mid, float min, float max, 
01808                                  int rev, int posterize) {
01809   scene->set_colorscale_params(min, mid, max, rev, posterize);
01810   commandQueue->runcommand(new CmdColorScaleSettings(mid, min, max, rev, posterize));
01811   return 1;
01812 }
01813 
01814 int VMDApp::colorscale_setmethod(int method) {
01815   if (method < 0 || method >= scene->num_colorscale_methods()) return 0;
01816   scene->set_colorscale_method(method);
01817   commandQueue->runcommand(new CmdColorScaleMethod(
01818         scene->colorscale_method_name(method)));
01819   return 1;
01820 }
01821   
01822   
01823 int VMDApp::logfile_read(const char *path) {
01824   uiText->read_from_file(path);
01825   return 1;
01826 }
01827 
01828 int VMDApp::save_state() {
01829   char *file = vmd_choose_file(
01830     "Enter filename to save current VMD state:",  // Title
01831     "*.vmd",                                      // extension
01832     "VMD files",                                  // label
01833     1                                             // do_save
01834   );
01835   if (!file)
01836     return 1;
01837   int retval = uiText->save_state(file);
01838   delete [] file;
01839   return retval;
01840 }
01841  
01842 int VMDApp::num_molecules() {
01843   return moleculeList->num();
01844 }
01845 
01846 
01847 // This creates a blank molecule, for use by "mol new atoms" and the like...
01848 int VMDApp::molecule_new(const char *name, int natoms, int docallbacks) {
01849   PROFILE_PUSH_RANGE("VMDApp::molecule_new()", 5);
01850 
01851   // if we aren't given a name for the molecule, use a temp name
01852   Molecule *newmol = new Molecule((name == NULL) ? "molecule" : name,
01853                                   this, &(scene->root));
01854   moleculeList->add_molecule(newmol);
01855   int molid = newmol->id();
01856 
01857   // If we aren't given a name for the molecule, we auto-generate one
01858   // from the assigned molid.
01859   if (name == NULL) {
01860     char buf[30];
01861     sprintf(buf, "molecule%d", molid);
01862 #if 1
01863     // We rename the molecule for ourselves without calling molecule_rename()
01864     // in order to avoid triggering extra callbacks that cause expensive 
01865     // GUI redraws.
01866     newmol->rename(buf);
01867 
01868     // Add item to Molecule color category; default color should be the same as
01869     // the original molecule.  
01870     int ind = moleculeList->colorCatIndex[MLCAT_MOLECULES];
01871     scene->add_color_item(ind, buf, molid % VISCLRS);
01872 #else
01873     molecule_rename(molid, buf);
01874 #endif
01875   }
01876 
01877   if (natoms > 0) {
01878     int i;
01879     newmol->init_atoms(natoms);
01880 
01881     float *charge = newmol->charge();
01882     float defcharge = newmol->default_charge("X");
01883     for (i=0; i<natoms; i++)
01884       charge[i] = defcharge;
01885 
01886     float *mass = newmol->mass();
01887     float defmass = newmol->default_mass("X");
01888     for (i=0; i<natoms; i++)
01889       mass[i] = defmass;
01890 
01891     float *radius = newmol->radius();
01892     float defradius = newmol->default_radius("X");
01893     for (i=0; i<natoms; i++)
01894       radius[i] = defradius;
01895 
01896     float *beta = newmol->beta();
01897     float defbeta = newmol->default_beta();
01898     for (i=0; i<natoms; i++)
01899       beta[i] = defbeta;
01900 
01901     float *occupancy = newmol->occupancy();
01902     float defoccupancy = newmol->default_occup();
01903     for (i=0; i<natoms; i++)
01904       occupancy[i] = defoccupancy;
01905 
01906     // add all of the atoms in a single call, looping internally in add_atoms()
01907     if (0 > newmol->add_atoms(natoms, "X", "X", 0, "UNK", 0, "", "", " ", "")) {
01908       // if an error occured while adding an atom, we should delete
01909       // the offending molecule since the data is presumably inconsistent,
01910       // or at least not representative of what we tried to load
01911       msgErr << "VMDApp::molecule_new: molecule creation aborted" << sendmsg;
01912       return -1; // signal failure
01913     }
01914   }
01915 
01916   if (docallbacks) {
01917     commandQueue->runcommand(new CmdMolNew);
01918     commandQueue->runcommand(new MoleculeEvent(molid, MoleculeEvent::MOL_NEW));
01919     commandQueue->runcommand(new InitializeStructureEvent(molid, 1));
01920   }
01921 
01922   PROFILE_POP_RANGE();
01923 
01924   return molid; 
01925 } 
01926 
01927 
01928 int VMDApp::molecule_from_selection_list(const char *name, int mergemode,
01929                                          int numsels, AtomSel **sellist, 
01930                                          int docallbacks) {
01931   PROFILE_PUSH_RANGE("VMDApp::molecule_from_selection_lis()", 3);
01932 
01933   // sanity check on contents of atom selection list
01934   int natoms=0;
01935   int selidx, i=0, j=0;
01936   int havecoords=0, allhavecoords=0;
01937   for (selidx=0; selidx<numsels; selidx++) {
01938     natoms += sellist[selidx]->selected;
01939     if (sellist[selidx]->coordinates(moleculeList) != NULL)
01940       havecoords++;
01941   } 
01942   if (havecoords==numsels) {
01943     allhavecoords=1;
01944   }
01945   havecoords = (havecoords != 0);
01946   msgInfo << "Building new molecule with " << natoms 
01947           << " atoms from " << numsels << " selections." << sendmsg;
01948   if (allhavecoords) {
01949     msgInfo << "All atoms will be assigned atomic coordinates." << sendmsg;
01950   } else if (havecoords) {
01951     msgInfo << "Some atoms will be assigned atomic coordinates." << sendmsg;
01952   } else {
01953     msgInfo << "No atomic atomic coordinates assigned from selection list." << sendmsg;
01954   }
01955 
01956   // if we aren't given a name for the molecule, use a temp name
01957   Molecule *newmol = new Molecule((name == NULL) ? "molecule" : name,
01958                                   this, &(scene->root));
01959   moleculeList->add_molecule(newmol);
01960   int molid = newmol->id();
01961 
01962   // If we aren't given a name for the molecule, we auto-generate one
01963   // from the assigned molid.
01964   if (name == NULL) {
01965     char buf[30];
01966     sprintf(buf, "molecule%d", molid);
01967 #if 1
01968     // We rename the molecule for ourselves without calling molecule_rename()
01969     // in order to avoid triggering extra callbacks that cause expensive 
01970     // GUI redraws.
01971     newmol->rename(buf);
01972 
01973     // Add item to Molecule color category; default color should be the same as
01974     // the original molecule.  
01975     int ind = moleculeList->colorCatIndex[MLCAT_MOLECULES];
01976     scene->add_color_item(ind, buf, molid % VISCLRS);
01977 #else
01978     molecule_rename(molid, buf);
01979 #endif
01980   }
01981 
01982   // initialize molecule and copy data from selected atoms into the
01983   // final molecule structure 
01984   newmol->init_atoms(natoms);
01985 
01986   // add a timestep for atomic coordinates, if we have them
01987   Timestep *ts = NULL;
01988   if (havecoords) {
01989     ts = new Timestep(natoms);
01990     newmol->append_frame(ts);
01991   }
01992 
01993   float *charge = newmol->charge();
01994   float *mass = newmol->mass();
01995   float *radius = newmol->radius();
01996   float *beta = newmol->beta();
01997   float *occupancy = newmol->occupancy();
01998 
01999   int naidx=0;
02000   for (selidx=0; selidx<numsels; selidx++) {
02001     const AtomSel *s = sellist[selidx];
02002     Molecule *sm = moleculeList->mol_from_id(s->molid());
02003 
02004 #if 0
02005     printf("selected mol[%d]: '%s'\n" 
02006            "                 %d atoms, %d residues, %d frags, %d protein, %d nucleic,\n"
02007            "                 %d selected first: %d last: %d\n", 
02008       s->molid(), sm->molname(),
02009       sm->nAtoms, sm->nResidues, sm->nFragments, 
02010       sm->nProteinFragments, sm->nNucleicFragments,
02011       s->selected, s->firstsel, s->lastsel);
02012 #endif
02013 
02014     // build a mapping from original atom indices to new atom indices
02015     int *atomindexmap = (int *) calloc(1, sm->nAtoms*sizeof(int));
02016 
02017     // initialize the atom index map to an invalid atom index value, so that
02018     // we can use this to eliminate bonds to atoms that aren't selected.
02019     for (j=0; j<sm->nAtoms; j++)
02020       atomindexmap[j] = -1;
02021 
02022     const float *s_charge = sm->charge();
02023     const float *s_mass = sm->mass();
02024     const float *s_radius = sm->radius();
02025     const float *s_beta = sm->beta();
02026     const float *s_occupancy = sm->occupancy();
02027 
02028     const Timestep *s_ts = s->timestep(moleculeList);
02029 
02030     // copy PBC unit cell information from first selection, when possible
02031     if (selidx == 0 && ts != NULL && s_ts != NULL) {
02032       ts->a_length = s_ts->a_length;
02033       ts->b_length = s_ts->b_length;
02034       ts->c_length = s_ts->c_length;
02035       ts->alpha = s_ts->alpha;
02036       ts->beta  = s_ts->beta;
02037       ts->gamma = s_ts->gamma;
02038     }
02039 
02040     int saidx=s->firstsel;
02041     while (saidx<=s->lastsel) {
02042       if (s->on[saidx]) {
02043         const MolAtom *satm = sm->atom(saidx);
02044 #if 0
02045         printf("Adding satom[%d, %p] as atom[%d] nameidx: %d '%s'\n", 
02046                saidx, satm, naidx, satm->nameindex,
02047                sm->atomNames.name(satm->nameindex));
02048 #endif
02049 
02050         newmol->add_atoms(1, 
02051                           sm->atomNames.name(satm->nameindex), 
02052                           sm->atomTypes.name(satm->typeindex),
02053                           satm->atomicnumber,
02054                           sm->resNames.name(satm->resnameindex),
02055                           satm->resid,
02056                           sm->chainNames.name(satm->chainindex),
02057                           sm->segNames.name(satm->segnameindex),
02058                           satm->insertionstr,
02059                           sm->altlocNames.name(satm->altlocindex));
02060 
02061         // copy atomic coordinates and other per-atom data if possible
02062         if (ts != NULL && s_ts != NULL) {
02063 #if 0
02064           printf("Copying atomic coordinates for atom[%d] from orig[%d]...\n", naidx, saidx);
02065 #endif
02066           long naddr = naidx*3;
02067           long saddr = saidx*3;
02068 
02069           // copy atomic coordinates
02070           ts->pos[naddr    ] = s_ts->pos[saddr    ];
02071           ts->pos[naddr + 1] = s_ts->pos[saddr + 1];
02072           ts->pos[naddr + 2] = s_ts->pos[saddr + 2];
02073 
02074           // XXX copy velocities, user fields, etc
02075         }
02076 
02077         // copy contents of the other per-atom fields
02078         charge[naidx] = s_charge[saidx];
02079         mass[naidx] = s_mass[saidx];
02080         radius[naidx] = s_radius[saidx];
02081         beta[naidx] = s_beta[saidx];
02082         occupancy[naidx] = s_occupancy[saidx];
02083      
02084         // build index map for bond/angle/dihedral/cterms
02085         atomindexmap[saidx] = naidx;
02086 
02087         naidx++; // increment total count of atoms built in new mol
02088       }
02089 
02090       // copy dataset flags from parent molecule(s)
02091       newmol->datasetflags |= sm->datasetflags;
02092 
02093       saidx++; // increment selected molecule atom index
02094     }
02095 
02096     // copy bonds to atoms that are also included in the selection
02097     j=0;
02098     for (saidx=s->firstsel; saidx<=s->lastsel; saidx++) {
02099       if (s->on[saidx]) {
02100         int newidx = naidx - s->selected + j; // index of new atom
02101         const MolAtom *satm = sm->atom(saidx);
02102 #if 0
02103         printf("atom[%d] (orig[%d]): %d bonds\n", newidx, saidx, satm->bonds);
02104 #endif
02105         int k;
02106         for (k=0; k<satm->bonds; k++) {
02107           float bondorder = 1;
02108           int bondtype = -1;
02109           int bto = satm->bondTo[k];
02110           int btmap = atomindexmap[bto];
02111           if (btmap >= 0) {
02112 #if 0
02113             printf("+bond from[%d] to [%d]\n", newidx, btmap);
02114 #endif
02115             // we must ensure that we do not duplicate bonds, so we
02116             // only add bonds to atoms with a higher index than our own
02117             if (btmap > newidx)
02118               newmol->add_bond(newidx, btmap, bondorder, bondtype);
02119           } 
02120 #if 0
02121           else {
02122             printf("-bond from[%d] to [%d] (%d to %d)\n", newidx, btmap, saidx, bto);
02123           }
02124 #endif
02125         }
02126         j++;
02127       }
02128     }
02129 
02130 #if 0
02131     printf("processing angles...\n");
02132 #endif
02133     // copy angles/dihedrals/impropers that are included in the selection
02134     int numangles = sm->num_angles();
02135     int numdihedrals = sm->num_dihedrals();
02136     int numimpropers = sm->num_impropers();
02137     int numcterms = sm->num_cterms();
02138 
02139     for (i=0; i<numangles; i++) {
02140       long i3addr = i*3L;
02141       int idx0 = atomindexmap[sm->angles[i3addr    ]];
02142       int idx1 = atomindexmap[sm->angles[i3addr + 1]];
02143       int idx2 = atomindexmap[sm->angles[i3addr + 2]];
02144       if ((idx0 >= 0) && (idx1 >= 0) && (idx2 >= 0)) {
02145         newmol->add_angle(idx0, idx1, idx2); 
02146       }
02147     }
02148 
02149 #if 0
02150     printf("processing dihedrals...\n");
02151 #endif
02152     for (i=0; i<numdihedrals; i++) {
02153       long i4addr = i*4L;
02154       int idx0 = atomindexmap[sm->dihedrals[i4addr    ]];
02155       int idx1 = atomindexmap[sm->dihedrals[i4addr + 1]];
02156       int idx2 = atomindexmap[sm->dihedrals[i4addr + 2]];
02157       int idx3 = atomindexmap[sm->dihedrals[i4addr + 3]];
02158       if ((idx0 >= 0) && (idx1 >= 0) && (idx2 >= 0) && (idx3 >= 0)) {
02159         newmol->add_dihedral(idx0, idx1, idx2, idx3);
02160       }
02161     }
02162 
02163 #if 0
02164     printf("processing numimpropers...\n");
02165 #endif
02166     for (i=0; i<numimpropers; i++) {
02167       long i4addr = i*4L;
02168       int idx0 = atomindexmap[sm->impropers[i4addr    ]];
02169       int idx1 = atomindexmap[sm->impropers[i4addr + 1]];
02170       int idx2 = atomindexmap[sm->impropers[i4addr + 2]];
02171       int idx3 = atomindexmap[sm->impropers[i4addr + 3]];
02172       if ((idx0 >= 0) && (idx1 >= 0) && (idx2 >= 0) && (idx3 >= 0)) {
02173         newmol->add_improper(idx0, idx1, idx2, idx3);
02174       }
02175     }
02176 
02177 #if 0
02178     printf("processing numcterms...\n");
02179 #endif
02180     for (i=0; i<numcterms; i++) {
02181       long i8addr = i*8L;
02182       int idx0 = atomindexmap[sm->cterms[i8addr    ]];
02183       int idx1 = atomindexmap[sm->cterms[i8addr + 1]];
02184       int idx2 = atomindexmap[sm->cterms[i8addr + 2]];
02185       int idx3 = atomindexmap[sm->cterms[i8addr + 3]];
02186       int idx4 = atomindexmap[sm->cterms[i8addr + 4]];
02187       int idx5 = atomindexmap[sm->cterms[i8addr + 5]];
02188       int idx6 = atomindexmap[sm->cterms[i8addr + 6]];
02189       int idx7 = atomindexmap[sm->cterms[i8addr + 7]];
02190 
02191       if ((idx0 >= 0) && (idx1 >= 0) && (idx2 >= 0) && (idx3 >= 0) &&
02192           (idx4 >= 0) && (idx5 >= 0) && (idx6 >= 0) && (idx7 >= 0)) {
02193         newmol->add_cterm(idx0, idx1, idx2, idx3, 
02194                           idx4, idx5, idx6, idx7);
02195       }
02196     }
02197 
02198     // XXX need to implement handling for 
02199     // angle types, dihedral types, and improper types (names)
02200 
02201     free(atomindexmap);
02202   }
02203 
02204 
02205 #if 0
02206     // add all of the atoms in a single call, looping internally in add_atoms()
02207     if (0 > newmol->add_atoms(natoms, "X", "X", 0, "UNK", 0, "", "", " ", "")) {
02208       // if an error occured while adding an atom, we should delete
02209       // the offending molecule since the data is presumably inconsistent,
02210       // or at least not representative of what we tried to load
02211       msgErr << "VMDApp::molecule_new: molecule creation aborted" << sendmsg;
02212       PROFILE_POP_RANGE();
02213       return -1; // signal failure
02214     }
02215 #endif
02216 
02217   // Cause VMD to analyze the newly-created atomic structure, so that
02218   // data such as the "residue" field get populated.
02219   newmol->analyze();
02220 
02221   if (docallbacks) {
02222     commandQueue->runcommand(new CmdMolNew);
02223     commandQueue->runcommand(new MoleculeEvent(molid, MoleculeEvent::MOL_NEW));
02224     commandQueue->runcommand(new InitializeStructureEvent(molid, 1));
02225   }
02226 
02227   PROFILE_POP_RANGE();
02228 
02229   return molid; 
02230 } 
02231 
02232 
02233 const char *VMDApp::guess_filetype(const char *filename) {
02234   const char *ext = strrchr(filename, '.');
02235   if (!ext) {
02236     // check for webpdb
02237     if (strlen(filename) == 4) {
02238       return "webpdb";
02239     }
02240     msgWarn << "Unable to ascertain filetype from filename '"
02241             << filename << "'; assuming pdb." << sendmsg;
02242     return "pdb";
02243   }
02244   ext++;
02245   char *s = strdup(ext);
02246   char *c = s;
02247   while (*c) { *c = tolower(*c); c++; }
02248   PluginList plugins;
02249   pluginMgr->plugins(plugins, "mol file reader", NULL);
02250   pluginMgr->plugins(plugins, "mol file converter", NULL);
02251   const char *bestname = NULL;
02252   int bestrank = 9999;
02253   for (int i=0; i<plugins.num(); i++) {
02254     // check against comma separated list of filename extensions, 
02255     // no spaces, as in: "pdb,ent,foo,bar,baz,ban"
02256     // Also keep track of the place in the list that the extension was
02257     // found - thus a plugin that lists the extension first can override
02258     // a plugin that comes earlier in the plugin list but lists the
02259     // extension later in its filename_extension string.
02260     MolFilePlugin p(plugins[i]);
02261     char *extbuf = strdup(p.extension());
02262     int extlen = strlen(extbuf);
02263     char *extcur = extbuf;
02264     char *extnext = NULL; 
02265     int currank = 1;
02266     while ((extcur - extbuf) < extlen) { 
02267       extnext = strchr(extcur, ','); // find next extension string
02268       if (extnext) {
02269         *extnext = '\0'; // NUL terminate this extension string
02270         extnext++;       // step to beginning of next extension string
02271       } else {
02272         extnext = extbuf + extlen; // no more extensions, last time through
02273       }
02274       if (!strcmp(s, extcur)) {
02275         if (!bestname || currank < bestrank) {
02276           bestname = p.name();
02277           bestrank = currank;
02278         }
02279       }
02280       extcur = extnext;
02281       ++currank;
02282     }
02283     free(extbuf);
02284   }
02285   free(s);
02286   return bestname;
02287 }
02288 
02289 int VMDApp::molecule_load(int molid, const char *filename, 
02290                           const char *filetype, const FileSpec *spec) {
02291   int original_molid = molid;
02292 
02293   // Call BaseMolecule::analyze() only once, when structure is first created.
02294   int first_structure = 0;
02295 
02296   // check for valid timestep parameters
02297   if (spec->last != -1 && spec->last < spec->first) {
02298     msgErr << "Invalid last frame: " << spec->last << sendmsg;
02299     return -1;
02300   }
02301   if (spec->stride < 1) {
02302     msgErr << "Invalid stride: " << spec->stride << sendmsg;
02303     return -1;
02304   }
02305 
02306   // if no filetype was given, try to obtain it from the filename.
02307   if (!filetype) {
02308     filetype = guess_filetype(filename);
02309     if (!filetype) {
02310       msgErr << "Could not determine filetype of file '" << filename 
02311              << "' from its name." << sendmsg;
02312       return -1;
02313     }
02314   }
02315 
02316   int waitfor = spec->waitfor;
02317   if (waitfor == 0 && molid == -1) {
02318     // It's not ok to load zero frames for a new molecule because coordinates
02319     // might be needed to determine bonds from atom distances.
02320     waitfor = 1;
02321     msgWarn << "Will load one coordinate frame for new molecule." << sendmsg;
02322   }
02323   
02324   // Prefer to use a direct reader plugin over a translator, if one
02325   // is available.  If not, then attempt to use a translator.
02326   vmdplugin_t *p = get_plugin("mol file reader", filetype);
02327   if (!p) p = get_plugin("mol file converter", filetype);
02328   if (!p) {
02329     msgErr << "Cannot read file of type " << filetype << sendmsg;
02330     return -1;
02331   }
02332   MolFilePlugin *plugin = new MolFilePlugin(p);
02333   if (plugin->init_read(filename)) {
02334     msgErr << "Could not read file " << filename << sendmsg;
02335     delete plugin;
02336     return -1;
02337   }
02338 
02339   // Check if VMD has to use page-aligned memory allocations for
02340   // timestep data, to allow for fast kernel-bypass unbuffered I/O APIs
02341   // Note: we make this call after the plugin's open_read() API has been
02342   // called, but before the first call to read_structure(), to ensure
02343   // that the called plugin sees that we have queried the required memory
02344   // alignment page size for all per-timestep data. 
02345   int ts_page_align_sz = 1;
02346   if (plugin->can_read_pagealigned_timesteps()) {
02347     // Determine whether a given file on a local or remote filesystem. 
02348     // We don't engage kernel-bypass direct-I/O when reading from
02349     // remote filesystems, as it turns out that filesystem caching
02350     // mechanisms like the Linux 'cachefilesd' daemon interpret
02351     // Unix direct-I/O (e.g. O_DIRECT) calls to be NFS-cache-bypassing  
02352     // I/O operations, which is not what we want in that particular case.
02353     // We want local NFS caches to be utilized rather than hitting the 
02354     // network, so in the case of remote filesystems we now revert to
02355     // normal I/O.  We only engage kernel-bypass I/O when the file of
02356     // interest resides on a local filesystem where there are no 
02357     // surprising side effects from direct-I/O.  This is particularly
02358     // beneficial on the NVIDIA DGX-2 which incorporates a large 30+TB
02359     // RAID-0 NFS cache, as an example.
02360     int fslocality = vmd_fstype_locality(filename);
02361 
02362     if (fslocality == VMD_FS_IS_REMOTE) {
02363       msgInfo << "Kernel-bypass direct-I/O disabled for remote filesystem" 
02364               << sendmsg;
02365     }
02366 
02367 #if vmdplugin_ABIVERSION > 17
02368     // If we don't query the page alignment size, the molfile plugin
02369     // will have to assume that we can't support kernel-bypassing
02370     // block-based direct-I/O, and will revert to using normal I/O.
02371     if (fslocality != VMD_FS_IS_REMOTE) {
02372       ts_page_align_sz = plugin->read_timestep_pagealign_size();
02373     }
02374 #endif
02375   }
02376 
02377   // to avoid excessive error handling cleanup, we only push the 
02378   // profiler marker when we've made it through 80% of the error checks
02379   PROFILE_PUSH_RANGE("VMDApp::molecule_load()", 5);
02380 
02381   Molecule *newmol = NULL;
02382   if (molid == -1) {
02383 #if 1
02384     // don't trigger callbacks for MOL_NEW etc yet, as we will be triggering
02385     // more of them below, and we wish to prevent the GUIs from exhibiting
02386     // quadratic behavior -- they regen their molecule choosers from scratch
02387     // in any case where the count of molecules doesn't change (e.g. when
02388     // getting redundant molecule new events from the same load event)
02389     molid = molecule_new(filename, 0, 0);
02390 #else
02391     molid = molecule_new(filename, 0);
02392 #endif
02393   }
02394   newmol = moleculeList->mol_from_id(molid);
02395   if (!newmol) {
02396     msgErr << "Invalid molecule " << molid << sendmsg;
02397     delete plugin;
02398     PROFILE_POP_RANGE();
02399     return -1;
02400   }
02401 
02402   // We've committed to loading as much as we can from the file, so go ahead
02403   // and record it.  This needs to be done before the InitializeStructure
02404   // event is triggered so that the list of filenames for the molecule is
02405   // complete and the filename can be used by Tcl/Python scripts that want
02406   // to process the filename when the InitializeStructure even occurs.
02407   char specstr[8192];
02408   sprintf(specstr, "first %d last %d step %d filebonds %d autobonds %d",
02409           spec->first, spec->last, spec->stride, 
02410           spec->filebonds, spec->autobonds);
02411   newmol->record_file(filename, filetype, specstr);
02412 
02413   //
02414   // Molecule file metadata
02415   // 
02416   if (plugin->can_read_metadata()) {
02417     if (plugin->read_metadata(newmol)) {
02418       msgErr << "Error reading metadata." << sendmsg;
02419     } 
02420   } else {
02421     // each file must have something, even if blank 
02422     newmol->record_database("", "");
02423     newmol->record_remarks("");
02424   }
02425  
02426   // 
02427   // Atomic structure and coordinate data
02428   //
02429   if (plugin->can_read_structure()) {
02430     if (!newmol->has_structure()) {
02431       // if the plugin can read structure data and there are a non-zero
02432       // number of atoms, we proceed with reading it, otherwise we bail out
02433       // of reading the structure, consider the outcome as having no structure,
02434       // and continue parsing for other data, e.g., file blocks containing
02435       // rawgraphics, density maps, or other contents independent of atomic
02436       // structure information.  Handling of the zero-atoms case is
02437       // required for correct handling of some of the (nascent) 
02438       // PDB hybrid modeling structure files hosted at PDB-Dev that contain
02439       // no atomic structure and only graphics glyph objects.
02440       // In this case, it is not acceptable to get MOLFILE_NUMATOMS_UNKNOWN,
02441       // since we must have an atom count to initialize structure information.
02442       if (plugin->natoms() > 0) {
02443         msgInfo << "Using plugin " << filetype << " for structure file " 
02444                 << filename << sendmsg;
02445 
02446         int rc = plugin->read_structure(newmol, spec->filebonds, spec->autobonds);
02447 
02448         // it's not an error to get no structure data from formats that
02449         // don't always contain it, so only report an error when we 
02450         // expected to get structure data and got an error instead.
02451         if (rc != MOLFILE_SUCCESS && rc != MOLFILE_NOSTRUCTUREDATA) {
02452           // tell the user something went wrong, but keep going and try to
02453           // read other information in the file.  Perhaps it's better to
02454           // stop immediately and create no molecule if something goes wrong
02455           // at this stage?
02456           msgErr << "molecule_structure: Unable to read structure for molecule "
02457                  << molid << sendmsg;
02458           if (rc == MOLFILE_ERROR) {
02459             msgErr << "molecule_structure: severe error indicated by plugin "
02460                    << "aborting loading of molecule " << molid << sendmsg;
02461             delete plugin;
02462             PROFILE_POP_RANGE();
02463             return -1;
02464           }
02465         }
02466 
02467         // initialize structure if we loaded with no errors
02468         if (rc == MOLFILE_SUCCESS) {
02469           first_structure = 1;
02470           commandQueue->runcommand(new InitializeStructureEvent(molid, 1));
02471         }
02472       }
02473     } else {
02474       // the molecule already has structure information, so we only look for
02475       // extra/optional structure data.
02476       int rc = plugin->read_optional_structure(newmol, spec->filebonds);
02477       if (rc != MOLFILE_SUCCESS && rc != MOLFILE_NOSTRUCTUREDATA) {
02478         msgErr << 
02479           "Error reading optional structure information from coordinate file "
02480           << filename << sendmsg;
02481         msgErr << "Will ignore structure information in this file." << sendmsg;
02482       }
02483     }
02484   } else {
02485     // Can't read structure, but some plugins (e.g. dcd) can initialize the
02486     // atom number.  Do this if possible
02487     // This implies natoms != MOLFILE_NUMATOMS_UNKNOWN
02488     if (plugin->natoms() > 0) {
02489       if (!newmol->init_atoms(plugin->natoms())) {
02490         msgErr << "Invalid number of atoms in file: " << plugin->natoms()
02491                << sendmsg;
02492       }
02493     }
02494   }
02495 
02496 
02497   //
02498   // Read QM metadata and the actual data in one swoop
02499   // for now. We might have to separate these later.
02500   // 
02501   if (plugin->can_read_qm()) {
02502     if (plugin->read_qm_data(newmol)) {
02503       msgErr << "Error reading metadata." << sendmsg;
02504     } 
02505   }
02506   
02507 
02508   //
02509   // Volumetric data
02510   //   We proceed with attempting to volumetric density maps for any plugin
02511   //   that advertises the possibility of their existence.  This is done 
02512   //   independently of the availability of any atomic structure information. 
02513   if (plugin->can_read_volumetric()) {
02514     if (plugin->read_volumetric(newmol, spec->nvolsets, spec->setids)) {
02515       msgErr << "Error reading volumetric data." << sendmsg;
02516     } else {
02517       scene_resetview_newmoldata(); // reset the view so we can see the dataset.
02518       commandQueue->runcommand(new CmdMolVolume(molid));
02519     }
02520   }
02521 
02522 
02523   // 
02524   // Raw graphics
02525   //   We proceed with attempting to read graphics objects for any plugin
02526   //   that advertises the possibility of their existence.  This is done 
02527   //   independently of the availability of any atomic structure information. 
02528   if (plugin->can_read_graphics()) {
02529     if (plugin->read_rawgraphics(newmol, scene)) {
02530       msgErr << "Reading raw graphics failed." << sendmsg;
02531     } else {
02532       scene_resetview_newmoldata(); // reset the view so we can see the dataset.
02533     }
02534   }
02535 
02536   //
02537   // Timesteps:
02538   //   At present we only read timesteps if we have a non-zero atom count,
02539   //   or the trajectory plugin returns MOLFILE_NUMATOMS_UNKNOWN, indicating
02540   //   that it has to be paired with a struture file containing a known
02541   //   atom count.  This is needed by AMBER CRD files, among others.
02542   //   It may become necessary to alter this logic if we later on have
02543   //   trajectory file formats that mix in non-atomic information that is
02544   //   present independent of any atomic coordinates.
02545   if ((plugin->can_read_timesteps() || plugin->can_read_qm_timestep()) &&
02546       ((plugin->natoms()==MOLFILE_NUMATOMS_UNKNOWN) || (plugin->natoms()>0))) {
02547     msgInfo << "Using plugin " << filetype << " for coordinates from file " 
02548             << filename << sendmsg;
02549 
02550     // Report use of direct block-based I/O when applicable
02551     if (ts_page_align_sz > 1)
02552       msgInfo << "  Direct I/O block size: " << ts_page_align_sz << sendmsg;
02553 
02554     if (!newmol->nAtoms) {
02555       msgErr << "Some frames from file '" << filename << "' could not be loaded"
02556         << sendmsg;
02557       msgErr << "because the number of atoms could not be determined.  Load a"
02558         << sendmsg;
02559       msgErr << "structure file first, then try loading this file again." << sendmsg;
02560     } else {
02561       // CoorPluginData also checks whether it has to use page-aligned 
02562       // memory allocations for incoming timestep data, to allow for 
02563       // fast kernel-bypass unbuffered I/O APIs, handling of padded and
02564       // aligned allocations is then taken care of in Timestep constructors
02565       CoorPluginData *data = new CoorPluginData(
02566           filename, newmol, plugin, 1, spec->first, spec->stride, spec->last);
02567 
02568 #if 0
02569       // Abort if there was a problem initializing coordinates, such as if
02570       // number of atoms doesn't match the topology. The plugin field is
02571       // used as a canary in the CoorPluginData constructor for this purpose.
02572       if (!data->is_valid()) {
02573         msgErr << "Problem loading coordinate data. Aborting loading of "
02574                << "molecule " << molid << sendmsg;
02575         delete data;
02576         delete plugin;
02577         PROFILE_POP_RANGE();
02578         return -1;
02579       }
02580 #endif
02581 
02582       newmol->add_coor_file(data);
02583       if (waitfor < 0) {
02584         // drain the I/O queue of all frames, even those that didn't necessarily
02585         // come from this file.
02586         while (newmol->next_frame());
02587       } else {
02588         // read waitfor frames.
02589         for (int i=0; i<waitfor; i++)
02590           if (!newmol->next_frame()) break;
02591       }
02592     }
02593   } else {
02594     // Delete the plugin unless timesteps were loaded, in which case the 
02595     // plugin will be deleted by the CoorPluginData object.
02596     delete plugin;
02597     plugin = NULL;
02598   }
02599 
02600   // Now go back and analyze structure, since we may have had to load
02601   // timesteps first.
02602   if (first_structure) {
02603     // build structure information for this molecule
02604     newmol->analyze(); 
02605 
02606     // Must add color names here because atom names and such aren't defined
02607     // until there's a molecular structure.
02608     moleculeList->add_color_names(moleculeList->mol_index_from_id(molid));
02609 
02610     // force all colors and reps to be recalculated, since this may be 
02611     // loaded into a molecule that didn't previously contain atomic data
02612     newmol->force_recalc(DrawMolItem::COL_REGEN | DrawMolItem::SEL_REGEN);
02613 
02614     // since atom color definitions are now established, create a new 
02615     // representation using the default parameters.
02616     moleculeList->set_color((char *)moleculeList->default_color());
02617     moleculeList->set_representation((char *)moleculeList->default_representation());
02618     moleculeList->set_selection(moleculeList->default_selection());
02619     moleculeList->set_material((char *)moleculeList->default_material());
02620     molecule_addrep(newmol->id());
02621     scene_resetview_newmoldata(); // reset the view so we can see the dataset.
02622   }
02623 
02624   // If the molecule doesn't have any reps yet and we have volume data,
02625   // add a new Isosurface rep.
02626   if (!newmol->components() && newmol->num_volume_data()) {
02627     molecule_set_style("Isosurface");
02628     molecule_addrep(newmol->id());
02629   }
02630 
02631   commandQueue->runcommand(new CmdMolLoad(original_molid, filename, filetype, 
02632                            spec));
02633 
02634   PROFILE_POP_RANGE();
02635   return molid;
02636 }
02637 
02638 
02639 int VMDApp::molecule_savetrajectory(int molid, const char *fname, 
02640                                     const char *type, const FileSpec *spec) {
02641   Molecule *newmol = moleculeList->mol_from_id(molid);
02642   if (!newmol) {
02643     msgErr << "Invalid molecule id " << molid << sendmsg;
02644     return -1;
02645   }
02646   if (fname == NULL) {
02647     msgErr << "Invalid NULL filename string" << sendmsg;
02648     return -1;
02649   }
02650 
02651   int first = spec->first;
02652   int last = spec->last;
02653   int stride = spec->stride;
02654   int waitfor = spec->waitfor;
02655   int nframes = 0;
02656   int natoms = 0;
02657   const int *selection = spec->selection;
02658   CoorData *data = NULL;
02659   int savevoldata = (newmol->num_volume_data() > 0) && (spec->nvolsets != 0);
02660 
02661   // Determine number of atoms to write.
02662   natoms = newmol->nAtoms;
02663   if (selection) {
02664     natoms=0;
02665     // the selection cannot change as the trajectory is written out,
02666     // so this is a safe way to count selected atoms
02667     for (int i=0; i<newmol->nAtoms; i++)
02668       natoms += selection[i] ? 1 : 0;
02669   }
02670 
02671   // validate timesteps if we actually have atomic coordinates to write
02672   if (natoms > 0) {
02673     if (last == -1)
02674       last = newmol->numframes() - 1;
02675 
02676     if (last < first && last >= 0) {
02677       msgErr << "Invalid last frame: " << last << sendmsg;
02678       return -1;
02679     }
02680     
02681     if (stride == -1 || stride == 0)
02682       stride = 1; // save all frames 
02683 
02684     if (stride < 1) {
02685       msgErr << "Invalid stride: " << stride << sendmsg;
02686       return -1;
02687     }
02688 
02689     nframes = (last-first)/stride + 1;
02690     if (nframes < 1 && !savevoldata) {
02691       msgInfo << "Save Trajectory: 0 frames specified; no coordinates written."
02692               << sendmsg;
02693       return 0;
02694     }
02695 
02696     if (natoms < 1 && !savevoldata) {
02697       msgInfo << "Save Trajectory: 0 atoms in molecule or selection; no coordinates written."
02698               << sendmsg;
02699       return -1;
02700     }
02701   }
02702 
02703   // Prefer to use a direct reader plugin over a translator, if one
02704   // is available.  If not, then attempt to use a translator.
02705   vmdplugin_t *p = get_plugin("mol file reader", type);
02706   if (!p) p = get_plugin("mol file converter", type);
02707   MolFilePlugin *plugin = NULL;
02708   if (p) {
02709     plugin = new MolFilePlugin(p);
02710     if (plugin->init_write(fname, natoms)) {
02711       msgErr << "Unable to open file " << fname << " of type " << type
02712              << " for writing frames." << sendmsg;
02713       delete plugin;
02714       return -1;
02715     }
02716     data = new CoorPluginData(fname, newmol, plugin, 0, first, stride, last,
02717                               selection);
02718   } else {
02719     msgErr << "Unknown coordinate file type " << type << sendmsg;
02720     return -1;
02721   }
02722   if (data == NULL) {
02723     msgErr << "NULL data returned by plugin " << sendmsg;
02724     return -1;
02725   }    
02726   msgInfo << "Opened coordinate file " << fname << " for writing.";
02727   msgInfo << sendmsg;
02728 
02729   // to avoid excessive error handling cleanup, we only push the 
02730   // profiler marker when we've made it through 80% of the error checks
02731   PROFILE_PUSH_RANGE("VMDApp::molecule_savetrajectory()", 5);
02732 
02733   // XXX if writing volume sets was requested, do it here, since CoorPluginData 
02734   // doesn't know about that type of data.  CoorPluginData should be using
02735   // a FileSpec struct.
02736   if (savevoldata) {
02737     if (plugin->can_write_volumetric()) {
02738       for (int i=0; i<spec->nvolsets; i++) {
02739         if (plugin->write_volumetric(newmol, spec->setids[i]) != 
02740             MOLFILE_SUCCESS) {
02741           msgErr << "Failed to write volume set " << spec->setids[i]
02742                  << sendmsg;
02743         }
02744       }
02745     } else {
02746       msgErr << "Cannot write volsets to files of type " << type << sendmsg;
02747     }
02748   }
02749   
02750   // write waitfor frames before adding to the Molecule's queue.
02751   int numwritten = 0;
02752   if (waitfor < 0) {
02753     while (data->next(newmol) == CoorData::NOTDONE)
02754       numwritten++;
02755   
02756     // Don't add to the I/O queue, just complete the I/O transaction 
02757     // synchronously and trigger any necessary callbacks.
02758     // This prevents analysis scripts that don't return control to the
02759     // main loop from queueing up large amounts of I/Os that only needed
02760     // file closures and memory frees to be completed.
02761     newmol->close_coor_file(data);
02762   } else if (waitfor > 0) {
02763     for (int i=0; i<waitfor; i++) {
02764       if (data->next(newmol) == CoorData::DONE) break;
02765         numwritten++;
02766     }
02767 
02768     // Add the I/O to the asynchronous queue and let it continue 
02769     // with subsequent main loop event polling/updates.
02770     newmol->add_coor_file(data);
02771   }
02772 
02773   commandQueue->runcommand(new CmdAnimWriteFile(molid, fname, type,
02774                            first, last, stride));
02775 
02776   PROFILE_POP_RANGE();
02777 
02778   return numwritten;
02779 }
02780  
02781 
02782 int VMDApp::molecule_deleteframes(int molid, int first, int last, 
02783                                    int stride) {
02784   Molecule *mol = moleculeList->mol_from_id(molid);
02785   if (!mol) {
02786     msgErr << "Invalid molecule id " << molid << sendmsg;
02787     return 0;
02788   }
02789   if (!mol->numframes()) return TRUE;
02790 
02791   if (last == -1)
02792     last = mol->numframes()-1;
02793   if (last < first) {
02794     msgErr << "Invalid last frame: " << last << sendmsg;
02795     return 0;
02796   }
02797   
02798   if (stride==-1) stride=0; //delete all frames in range
02799   if (stride < 0) {
02800     msgErr << "Invalid stride: " << stride << sendmsg;
02801     return 0;
02802   }
02803   
02804   // keep every stride frame btw first and last
02805   int indexshift = first; // as frames are deleted, indices are shifted
02806   for (int i=0; i<=last-first; i++) {
02807     if (!stride || i%stride) {
02808       mol->delete_frame(indexshift+i);
02809       indexshift--;
02810     }
02811   }
02812 
02813   commandQueue->runcommand(new CmdAnimDelete(molid, first, last, stride));
02814   return 1;
02815 }
02816 
02817 int VMDApp::molecule_index_from_id(int id) {
02818   if (id < 0) return -1;
02819   return moleculeList->mol_index_from_id(id);
02820 }
02821 int VMDApp::molecule_id(int i) {
02822   if (i < 0 || i >= num_molecules()) return -1;
02823   Molecule *m = moleculeList->molecule(i);
02824   if (m == NULL)
02825     return -1;
02826   return m->id();
02827 }
02828 int VMDApp::molecule_valid_id(int molid) {
02829   return (moleculeList->mol_from_id(molid) != NULL);
02830 }
02831 int VMDApp::molecule_cancel_io(int molid) {
02832   Molecule *m = moleculeList->mol_from_id(molid);
02833   if (!m) return 0;
02834   m->cancel();
02835   commandQueue->runcommand(new CmdMolCancel(molid));
02836   return 1;
02837 }
02838 
02839 int VMDApp::molecule_delete(int molid) {
02840   if (moleculeList->del_molecule(molid)) {
02841     commandQueue->runcommand(new CmdMolDelete(molid));
02842     commandQueue->runcommand(new InitializeStructureEvent(molid, 0));
02843     commandQueue->runcommand(new MoleculeEvent(molid, MoleculeEvent::MOL_DELETE));
02844     // XXX this has the side effect of altering the 'top' molecule.
02845     // At present the GUI is checking for MOL_DEL in addition to MOL_TOP,
02846     // but really it'd be nicer if we generated appropriate events for 
02847     // side effect cases like this.
02848     return 1;
02849   }
02850   return 0; 
02851 }
02852 
02853 int VMDApp::molecule_delete_all(void) {
02854   int i, nummols, rc;
02855   int *molidlist;
02856 
02857   rc = 0;
02858   nummols = num_molecules();
02859   molidlist = new int[nummols];
02860  
02861   // save molid translation list before we delete them all
02862   for (i=0; i<nummols; i++) {
02863     molidlist[i] = moleculeList->molecule(i)->id();
02864   }
02865 
02866   // delete all molecules and process molecule event callbacks
02867   if (moleculeList->del_all_molecules()) {
02868     for (i=0; i<nummols; i++) {
02869       int molid = molidlist[i];
02870       commandQueue->runcommand(new CmdMolDelete(molid));
02871       commandQueue->runcommand(new InitializeStructureEvent(molid, 0));
02872       commandQueue->runcommand(new MoleculeEvent(molid, MoleculeEvent::MOL_DELETE));
02873     }
02874 
02875     // XXX this has the side effect of altering the 'top' molecule.
02876     // At present the GUI is checking for MOL_DEL in addition to MOL_TOP,
02877     // but really it'd be nicer if we generated appropriate events for 
02878     // side effect cases like this.
02879     rc=1;
02880   }
02881 
02882   delete [] molidlist;
02883 
02884   return rc; 
02885 }
02886 
02887 int VMDApp::molecule_activate(int molid, int onoff) {
02888   int ind = moleculeList->mol_index_from_id(molid);
02889   if (ind < 0) return 0;
02890   if (onoff)
02891     moleculeList->activate(ind);
02892   else
02893     moleculeList->inactivate(ind);
02894   commandQueue->runcommand(new CmdMolActive(molid, onoff));
02895   return 1;
02896 }
02897 int VMDApp::molecule_is_active(int molid) {
02898   int ind = moleculeList->mol_index_from_id(molid);
02899   if (ind < 0) return 0;
02900   return moleculeList->active(ind);
02901 }
02902 int VMDApp::molecule_fix(int molid, int onoff) {
02903   int ind = moleculeList->mol_index_from_id(molid);
02904   if (ind < 0) return 0;
02905   if (onoff)
02906     moleculeList->fix(ind);
02907   else
02908     moleculeList->unfix(ind);
02909   commandQueue->runcommand(new CmdMolFix(molid, onoff));
02910   return 1;
02911 }
02912 int VMDApp::molecule_is_fixed(int molid) {
02913   int ind = moleculeList->mol_index_from_id(molid);
02914   if (ind < 0) return 0;
02915   return moleculeList->fixed(ind);
02916 }
02917 int VMDApp::molecule_display(int molid, int onoff) {
02918   int ind = moleculeList->mol_index_from_id(molid);
02919   if (ind < 0) return 0;
02920   if (onoff)
02921     moleculeList->show(ind);
02922   else
02923     moleculeList->hide(ind);
02924   commandQueue->runcommand(new CmdMolOn(molid, onoff));
02925   return 1;
02926 }
02927 int VMDApp::molecule_is_displayed(int molid) {
02928   int ind = moleculeList->mol_index_from_id(molid);
02929   if (ind < 0) return 0;
02930   return moleculeList->displayed(ind);
02931 }
02932 int VMDApp::molecule_make_top(int molid) {
02933   int ind = moleculeList->mol_index_from_id(molid);
02934   if (ind < 0) return 0;
02935   moleculeList->make_top(ind);
02936   commandQueue->runcommand(new CmdMolTop(molid));
02937   return 1;
02938 }
02939 int VMDApp::molecule_top() {
02940   Molecule *m = moleculeList->top();
02941   if (!m) return -1;
02942   return m->id();
02943 }
02944 int VMDApp::num_molreps(int molid) {
02945   Molecule *m = moleculeList->mol_from_id(molid);
02946   if (!m) return 0;
02947   return m->components();
02948 }
02949 const char *VMDApp::molrep_get_style(int molid, int repid) {
02950   if (repid < 0 || repid >= num_molreps(molid)) return NULL;
02951   DrawMolItem *item = moleculeList->mol_from_id(molid)->component(repid);
02952   if (item == NULL)
02953     return NULL;
02954   return item->atomRep->cmdStr;
02955 }
02956 int VMDApp::molrep_set_style(int molid, int repid, const char *style) {
02957   int ind = moleculeList->mol_index_from_id(molid);
02958   if (ind < 0) return 0;
02959   if (!moleculeList->change_repmethod(repid, ind, (char *)style)) return 0;
02960   commandQueue->runcommand(
02961     new CmdMolChangeRepItem(repid, molid, CmdMolChangeRepItem::REP, style));
02962   return 1;
02963 }
02964 const char *VMDApp::molrep_get_color(int molid, int repid) {
02965   if (repid < 0 || repid >= num_molreps(molid)) return NULL;
02966   DrawMolItem *item = moleculeList->mol_from_id(molid)->component(repid);
02967   if (item == NULL)
02968     return NULL;
02969   return item->atomColor->cmdStr;
02970 }
02971 int VMDApp::molrep_set_color(int molid, int repid, const char *color) {
02972   int ind = moleculeList->mol_index_from_id(molid);
02973   if (ind < 0) return 0;
02974   if (!moleculeList->change_repcolor(repid, ind, (char *)color)) return 0;
02975   commandQueue->runcommand(
02976     new CmdMolChangeRepItem(repid, molid, CmdMolChangeRepItem::COLOR, color));
02977   return 1;
02978 }
02979 const char *VMDApp::molrep_get_selection(int molid, int repid) {
02980   if (repid < 0 || repid >= num_molreps(molid)) return NULL;
02981   DrawMolItem *item = moleculeList->mol_from_id(molid)->component(repid);
02982   if (item == NULL)
02983     return NULL;
02984   return item->atomSel->cmdStr;
02985 }
02986 int VMDApp::molrep_set_selection(int molid, int repid, const char *selection) {
02987   int ind = moleculeList->mol_index_from_id(molid);
02988   if (ind < 0) return FALSE;
02989   if (!moleculeList->change_repsel(repid, ind, selection)) 
02990       return FALSE;
02991   commandQueue->runcommand(
02992     new CmdMolChangeRepItem(repid, molid, CmdMolChangeRepItem::SEL, selection));
02993   return TRUE;
02994 }
02995 int VMDApp::molrep_numselected(int molid, int repid) {
02996   if (repid >= num_molreps(molid)) return  -1;
02997   DrawMolItem *item = moleculeList->mol_from_id(molid)->component(repid);
02998   if (item == NULL)
02999     return -1;
03000   return item->atomSel->selected;
03001 }
03002 const char *VMDApp::molrep_get_material(int molid, int repid) {
03003   if (repid >= num_molreps(molid)) return NULL;
03004   DrawMolItem *item = moleculeList->mol_from_id(molid)->component(repid);
03005   if (item == NULL)
03006     return NULL;
03007   return materialList->material_name(item->curr_material());
03008 }
03009 int VMDApp::molrep_set_material(int molid, int repid, const char *material) {
03010   int ind = moleculeList->mol_index_from_id(molid);
03011   if (ind < 0) return 0;
03012   if (!moleculeList->change_repmat(repid, ind, (char *)material)) return 0;
03013   commandQueue->runcommand(
03014     new CmdMolChangeRepItem(repid, molid, CmdMolChangeRepItem::MAT, material));
03015   return 1;
03016 }
03017 const char *VMDApp::molecule_get_style() {
03018   return moleculeList->representation();
03019 }
03020 int VMDApp::molecule_set_style(const char *style) {
03021   if (!moleculeList->set_representation((char *)style))
03022     return 0;
03023   commandQueue->runcommand(new CmdMolRep(style));
03024   return 1;
03025 }
03026 const char *VMDApp::molecule_get_color() {
03027   return moleculeList->color();
03028 }
03029 int VMDApp::molecule_set_color(const char *color) {
03030   if (!moleculeList->set_color((char *)color)) 
03031     return 0;
03032   commandQueue->runcommand(new CmdMolColor(color));
03033   return 1;
03034 }
03035 const char *VMDApp::molecule_get_selection() {
03036   return moleculeList->selection();
03037 }
03038 int VMDApp::molecule_set_selection(const char *selection) {
03039   if (!moleculeList->set_selection(selection))
03040     return FALSE;
03041   commandQueue->runcommand(new CmdMolSelect(selection));
03042   return TRUE;
03043 }
03044 const char *VMDApp::molecule_get_material() {
03045   return moleculeList->material();
03046 }
03047 int VMDApp::molecule_set_material(const char *material) {
03048   if (!moleculeList->set_material((char *)material))
03049     return 0;
03050   commandQueue->runcommand(new CmdMolMaterial(material));
03051   return 1;
03052 }
03053 int VMDApp::molecule_addrep(int molid) {
03054   int ind = moleculeList->mol_index_from_id(molid);
03055   if (ind < 0) return 0;
03056   if (!moleculeList->add_rep(ind)) return 0;
03057   commandQueue->runcommand(new CmdMolAddRep(molid));
03058   return 1;
03059 }
03060 int VMDApp::molecule_modrep(int molid, int repid) {
03061   int ind = moleculeList->mol_index_from_id(molid);
03062   if (ind < 0) return 0;
03063   if (!moleculeList->change_rep(repid, ind)) return 0;
03064   commandQueue->runcommand(new CmdMolChangeRep(molid, repid));
03065   return 1;
03066 } 
03067 int VMDApp::molrep_delete(int molid, int repid) {
03068   int ind = moleculeList->mol_index_from_id(molid);
03069   if (ind < 0) return 0;
03070   if (!moleculeList->del_rep(repid, ind)) return 0;
03071   commandQueue->runcommand(new CmdMolDeleteRep(repid, molid));
03072   return 1;
03073 }
03074 
03075 int VMDApp::molrep_get_selupdate(int molid, int repid) {
03076   if (repid >= num_molreps(molid)) return 0;
03077   DrawMolItem *item = moleculeList->mol_from_id(molid)->component(repid);
03078   if (item == NULL || item->atomSel == NULL)
03079     return 0;
03080   return item->atomSel->do_update; 
03081 } 
03082 int VMDApp::molrep_set_selupdate(int molid, int repid, int onoff) {
03083   if (repid >= num_molreps(molid)) return 0;
03084   DrawMolItem *item = moleculeList->mol_from_id(molid)->component(repid);
03085   if (item == NULL || item->atomSel == NULL)
03086     return 0;
03087   item->atomSel->do_update = onoff;
03088   commandQueue->runcommand(new CmdMolRepSelUpdate(repid, molid, onoff));
03089   return 1;
03090 } 
03091 
03092 int VMDApp::molrep_set_colorupdate(int molid, int repid, int onoff) {
03093   if (repid >= num_molreps(molid)) return 0;
03094   DrawMolItem *item = moleculeList->mol_from_id(molid)->component(repid);
03095   if (item == NULL || item->atomColor == NULL)
03096     return 0;
03097   item->atomColor->do_update = onoff;
03098   if (onoff) item->force_recalc(DrawMolItem::COL_REGEN);
03099   commandQueue->runcommand(new CmdMolRepColorUpdate(repid, molid, onoff));
03100   return 1;
03101 } 
03102 int VMDApp::molrep_get_colorupdate(int molid, int repid) {
03103   if (repid >= num_molreps(molid)) return 0;
03104   DrawMolItem *item = moleculeList->mol_from_id(molid)->component(repid);
03105   if (item == NULL || item->atomColor == NULL)
03106     return 0;
03107   return item->atomColor->do_update;
03108 }
03109 
03110 int VMDApp::molrep_set_smoothing(int molid, int repid, int n) {
03111   if (repid < 0 || repid >= num_molreps(molid)) return FALSE;
03112   DrawMolItem *item = moleculeList->mol_from_id(molid)->component(repid);
03113   if (item->get_smoothing() == n) return TRUE;
03114   if (item->set_smoothing(n)) {
03115     item->force_recalc(DrawMolItem::MOL_REGEN);
03116     commandQueue->runcommand(new CmdMolSmoothRep(molid, repid, n));
03117     return TRUE;
03118   }
03119   return FALSE;
03120 }
03121 int VMDApp::molrep_get_smoothing(int molid, int repid) {
03122   if (repid < 0 || repid >= num_molreps(molid)) return -1;
03123   DrawMolItem *item = moleculeList->mol_from_id(molid)->component(repid);
03124   return item->get_smoothing();
03125 }
03126 
03127 int VMDApp::molrep_set_pbc(int molid, int repid, int pbc) {
03128   if (repid < 0 || repid >= num_molreps(molid)) return FALSE;
03129   DrawMolItem *item = moleculeList->mol_from_id(molid)->component(repid);
03130   item->set_pbc(pbc);
03131   commandQueue->runcommand(new CmdMolShowPeriodic(molid, repid, pbc));
03132   return TRUE;
03133 }
03134 int VMDApp::molrep_get_pbc(int molid, int repid) {
03135   if (repid < 0 || repid >= num_molreps(molid)) return FALSE;
03136   const DrawMolItem *item = moleculeList->mol_from_id(molid)->component(repid);
03137   return item->get_pbc();
03138 }
03139 
03140 int VMDApp::molrep_set_pbc_images(int molid, int repid, int n) {
03141   if (n < 1) return FALSE;
03142   if (repid < 0 || repid >= num_molreps(molid)) return FALSE;
03143   DrawMolItem *item = moleculeList->mol_from_id(molid)->component(repid);
03144   item->set_pbc_images(n);
03145   commandQueue->runcommand(new CmdMolNumPeriodic(molid, repid, n));
03146   return TRUE;
03147 }
03148 int VMDApp::molrep_get_pbc_images(int molid, int repid) {
03149   if (repid < 0 || repid >= num_molreps(molid)) return -1;
03150   const DrawMolItem *item = moleculeList->mol_from_id(molid)->component(repid);
03151   return item->get_pbc_images();
03152 }
03153 
03154 
03155 int VMDApp::molecule_add_instance(int molid, Matrix4 & inst) {
03156   Molecule *m = moleculeList->mol_from_id(molid);
03157   if (!m) return 0;
03158   m->add_instance(inst);
03159 
03160   // commandQueue->runcommand(new CmdMolVolume(molid));
03161   return 1;
03162 }
03163 int VMDApp::molecule_num_instances(int molid) {
03164   Molecule *m = moleculeList->mol_from_id(molid);
03165   if (!m) return -1;
03166   return m->num_instances();
03167 }
03168 int VMDApp::molecule_delete_all_instances(int molid) {
03169   Molecule *m = moleculeList->mol_from_id(molid);
03170   if (!m) return -1;
03171   m->clear_instances();
03172   // commandQueue->runcommand(new CmdMolVolume(molid));
03173   return 1;
03174 }
03175 
03176 int VMDApp::molrep_set_instances(int molid, int repid, int inst) {
03177   if (repid < 0 || repid >= num_molreps(molid)) return FALSE;
03178   DrawMolItem *item = moleculeList->mol_from_id(molid)->component(repid);
03179   item->set_instances(inst);
03180   commandQueue->runcommand(new CmdMolShowInstances(molid, repid, inst));
03181   return TRUE;
03182 }
03183 int VMDApp::molrep_get_instances(int molid, int repid) {
03184   if (repid < 0 || repid >= num_molreps(molid)) return FALSE;
03185   const DrawMolItem *item = moleculeList->mol_from_id(molid)->component(repid);
03186   return item->get_instances();
03187 }
03188 
03189 int VMDApp::molecule_set_dataset_flag(int molid, const char *dataflagstr,
03190                                       int setval) {
03191   int dataflag=BaseMolecule::NODATA;
03192   Molecule *m = moleculeList->mol_from_id(molid);
03193   if (!m) return 0;
03194 
03195   // which flag to set/clear
03196   if (!strcmp("insertion", dataflagstr)) {
03197     dataflag=BaseMolecule::INSERTION;
03198   } else if (!strcmp("occupancy", dataflagstr)) {
03199     dataflag=BaseMolecule::OCCUPANCY;
03200   } else if (!strcmp("beta", dataflagstr)) {
03201     dataflag=BaseMolecule::BFACTOR;
03202   } else if (!strcmp("mass", dataflagstr)) {
03203     dataflag=BaseMolecule::MASS;
03204   } else if (!strcmp("charge", dataflagstr)) {
03205     dataflag=BaseMolecule::CHARGE;
03206   } else if (!strcmp("radius", dataflagstr)) {
03207     dataflag=BaseMolecule::RADIUS;
03208   } else if (!strcmp("altloc", dataflagstr)) {
03209     dataflag=BaseMolecule::ALTLOC;
03210   } else if (!strcmp("atomicnumber", dataflagstr)) {
03211     dataflag=BaseMolecule::ATOMICNUMBER;
03212   } else if (!strcmp("bonds", dataflagstr)) {
03213     dataflag=BaseMolecule::BONDS;
03214   } else if (!strcmp("bondorders", dataflagstr)) {
03215     dataflag=BaseMolecule::BONDORDERS;
03216   } else if (!strcmp("bondtypes", dataflagstr)) {
03217     dataflag=BaseMolecule::BONDTYPES;
03218   } else if (!strcmp("angles", dataflagstr)) {
03219     dataflag=BaseMolecule::ANGLES;
03220   } else if (!strcmp("angletypes", dataflagstr)) {
03221     dataflag=BaseMolecule::ANGLETYPES;
03222   } else if (!strcmp("cterms", dataflagstr)) {
03223     dataflag=BaseMolecule::CTERMS;
03224   } else if (!strcmp("all", dataflagstr)) {
03225     dataflag=
03226       BaseMolecule::INSERTION    |
03227       BaseMolecule::OCCUPANCY    |
03228       BaseMolecule::BFACTOR      |
03229       BaseMolecule::MASS         |
03230       BaseMolecule::CHARGE       |
03231       BaseMolecule::RADIUS       |
03232       BaseMolecule::ALTLOC       |
03233       BaseMolecule::ATOMICNUMBER |
03234       BaseMolecule::BONDS        |
03235       BaseMolecule::BONDORDERS   |
03236       BaseMolecule::BONDTYPES    |
03237       BaseMolecule::ANGLES       |
03238       BaseMolecule::ANGLETYPES   |
03239       BaseMolecule::CTERMS;
03240   }
03241 
03242   // return an error if the flag string is unknown
03243   if (dataflag == BaseMolecule::NODATA)
03244     return 0;
03245 
03246   // set/unset the flag if we recognized it
03247   if (setval)
03248     m->set_dataset_flag(dataflag); 
03249   else
03250     m->unset_dataset_flag(dataflag); 
03251 
03252   return 1;
03253 }
03254 
03255 
03256 int VMDApp::molecule_reanalyze(int molid) {
03257   Molecule *m = moleculeList->mol_from_id(molid);
03258   if (!m) return 0;
03259 
03260   // (re)analyze the molecular structure, since bonds may have been changed
03261   m->analyze();
03262 
03263   // force all reps and selections to be recalculated
03264   m->force_recalc(DrawMolItem::COL_REGEN | 
03265                   DrawMolItem::MOL_REGEN |
03266                   DrawMolItem::SEL_REGEN);
03267 
03268   // regen secondary structure as well
03269   m->invalidate_ss();
03270 
03271   // log the command
03272   commandQueue->runcommand(new CmdMolReanalyze(molid));
03273   commandQueue->runcommand(new MoleculeEvent(molid, MoleculeEvent::MOL_REGEN));
03274   return TRUE;
03275 }
03276 int VMDApp::molecule_bondsrecalc(int molid) {
03277   Molecule *m = moleculeList->mol_from_id(molid);
03278   if (!m) return 0;
03279   if (m->recalc_bonds()) return 0;
03280   commandQueue->runcommand(new CmdMolBondsRecalc(molid));
03281   commandQueue->runcommand(new MoleculeEvent(molid, MoleculeEvent::MOL_REGEN));
03282   return 1;
03283 }
03284 int VMDApp::molecule_ssrecalc(int molid) {
03285   Molecule *m = moleculeList->mol_from_id(molid);
03286   if (!m) return FALSE;
03287   if (!m->recalc_ss()) return FALSE;
03288   commandQueue->runcommand(new CmdMolSSRecalc(molid));
03289   return TRUE;
03290 }
03291 int VMDApp::molecule_numatoms(int molid) {
03292   Molecule *m = moleculeList->mol_from_id(molid);
03293   if (!m) return -1;
03294   return m->nAtoms;
03295 }
03296 int VMDApp::molecule_numframes(int molid) {
03297   Molecule *m = moleculeList->mol_from_id(molid);
03298   if (!m) return -1;
03299   return m->numframes();
03300 } 
03301 int VMDApp::molecule_frame(int molid) {
03302   Molecule *m = moleculeList->mol_from_id(molid);
03303   if (!m) return -1;
03304   return m->frame();
03305 } 
03306 int VMDApp::molecule_dupframe(int molid, int frame) {
03307   Molecule *m = moleculeList->mol_from_id(molid);
03308   if (!m) {
03309     msgErr << "molecule_dupframe: invalid molecule" << sendmsg;
03310     return FALSE;
03311   }
03312   if (frame >= m->numframes()) {
03313     msgErr << "molecule_dupframe: frame out of range" << sendmsg;
03314     return FALSE;
03315   }
03316   if (frame == -1) {
03317     m->duplicate_frame(m->current());
03318   } else {
03319     m->duplicate_frame(m->get_frame(frame));
03320   }
03321   commandQueue->runcommand(new CmdAnimDup(frame, molid));
03322   return TRUE;
03323 }
03324 
03325 const char *VMDApp::molecule_name(int molid) {
03326   Molecule *m = moleculeList->mol_from_id(molid);
03327   if (!m) return NULL;
03328   return m->molname();
03329 } 
03330 int VMDApp::molecule_rename(int molid, const char *newname) {
03331   Molecule *m = moleculeList->mol_from_id(molid);
03332   if (!m) return 0;
03333   if (!newname) return 0;
03334   if (!m->rename(newname)) return 0;
03335   
03336   // Add item to Molecule color category; default color should be the same as
03337   // the original molecule.  
03338   int ind = moleculeList->colorCatIndex[MLCAT_MOLECULES];
03339   scene->add_color_item(ind, newname, m->id() % VISCLRS);
03340   
03341   commandQueue->runcommand(new CmdMolRename(molid, newname));
03342   commandQueue->runcommand(new MoleculeEvent(molid, MoleculeEvent::MOL_RENAME));
03343   return 1;
03344 }
03345 
03348 int VMDApp::molecule_orblocalize(int molid, int waveid) {
03349   Molecule *m = moleculeList->mol_from_id(molid);
03350   if (!m) return 0;
03351 
03352   float *expandedbasis = NULL;
03353   int *numprims = NULL;
03354   m->qm_data->expand_basis_array(expandedbasis, numprims);
03355 
03356   int i;
03357   for (i=0; i<m->numframes(); i++) {
03358     msgInfo << "Localizing orbitals for wavefunction " << waveid
03359             << " in frame " << i << sendmsg;
03360     m->qm_data->orblocalize(m->get_frame(i), waveid, expandedbasis, numprims);
03361   }
03362 
03363   delete [] expandedbasis;
03364   delete [] numprims;
03365   // XXX need to add commandQueue->runcommand()
03366   return 1;
03367 }
03368 
03369 int VMDApp::molecule_add_volumetric(int molid, const char *dataname, 
03370     const float origin[3], const float xaxis[3], const float yaxis[3],
03371     const float zaxis[3], int xsize, int ysize, int zsize, float *datablock) {
03372   PROFILE_PUSH_RANGE("VMDApp::molecule_add_volumetric()", 3);
03373  
03374   Molecule *m = moleculeList->mol_from_id(molid);
03375   if (!m) return 0;
03376   m->add_volume_data(dataname, origin, xaxis, yaxis, zaxis, xsize, ysize, 
03377     zsize, datablock);
03378 
03379   scene_resetview_newmoldata(); // reset the view so we can see the dataset.
03380   commandQueue->runcommand(new CmdMolVolume(molid));
03381 
03382   PROFILE_POP_RANGE();
03383   return 1;
03384 }
03385 
03386 int VMDApp::molecule_add_volumetric(int molid, const char *dataname, 
03387     const double origin[3], const double xaxis[3], const double yaxis[3],
03388     const double zaxis[3], int xsize, int ysize, int zsize, float *datablock) {
03389   PROFILE_PUSH_RANGE("VMDApp::molecule_add_volumetric()", 3);
03390   
03391   Molecule *m = moleculeList->mol_from_id(molid);
03392   if (!m) return 0;
03393   m->add_volume_data(dataname, origin, xaxis, yaxis, zaxis, xsize, ysize, 
03394     zsize, datablock);
03395 
03396   scene_resetview_newmoldata(); // reset the view so we can see the dataset.
03397   commandQueue->runcommand(new CmdMolVolume(molid));
03398 
03399   PROFILE_POP_RANGE();
03400   return 1;
03401 }
03402 
03403 void VMDApp::set_mouse_callbacks(int on) {
03404   mouse->set_callbacks(on);
03405 }
03406 
03407 void VMDApp::set_mouse_rocking(int on) {
03408   mouse->set_rocking(on);
03409 }
03410 
03411 int VMDApp::num_clipplanes() {
03412   return VMD_MAX_CLIP_PLANE;
03413 }
03414 int VMDApp::molrep_get_clipplane(int molid, int repid, int clipid,
03415                         float *center, float *normal, float *color, int *mode) {
03416   Molecule *mol = moleculeList->mol_from_id(molid);
03417   if (!mol) return 0;
03418   Displayable *d = mol->component(repid);
03419   if (!d) return 0;
03420   const VMDClipPlane *c = d->clipplane(clipid);
03421   if (!c) return 0;
03422   memcpy(center, c->center, 3L*sizeof(float));
03423   memcpy(normal, c->normal, 3L*sizeof(float));
03424   memcpy(color, c->color, 3L*sizeof(float));
03425   *mode = c->mode;
03426   return 1;
03427 }
03428 int VMDApp::molrep_set_clipcenter(int molid, int repid, int clipid,
03429                                  const float *center) {
03430   Molecule *mol = moleculeList->mol_from_id(molid);
03431   if (!mol) return 0;
03432   Displayable *d = mol->component(repid);
03433   if (!d) return 0;
03434   return d->set_clip_center(clipid, center);
03435 }
03436 int VMDApp::molrep_set_clipnormal(int molid, int repid, int clipid,
03437                                  const float *normal) {
03438   Molecule *mol = moleculeList->mol_from_id(molid);
03439   if (!mol) return 0;
03440   Displayable *d = mol->component(repid);
03441   if (!d) return 0;
03442   return d->set_clip_normal(clipid, normal);
03443 }
03444 int VMDApp::molrep_set_clipcolor(int molid, int repid, int clipid,
03445                                  const float *color) {
03446   Molecule *mol = moleculeList->mol_from_id(molid);
03447   if (!mol) return 0;
03448   Displayable *d = mol->component(repid);
03449   if (!d) return 0;
03450   return d->set_clip_color(clipid, color);
03451 }
03452 int VMDApp::molrep_set_clipstatus(int molid, int repid, int clipid, int mode) {
03453   Molecule *mol = moleculeList->mol_from_id(molid);
03454   if (!mol) return 0;
03455   Displayable *d = mol->component(repid);
03456   if (!d) return 0;
03457   return d->set_clip_status(clipid, mode);
03458 }
03459  
03460 const char *VMDApp::molrep_get_name(int molid, int repid) {
03461   Molecule *mol = moleculeList->mol_from_id(molid);  
03462   if (!mol) return NULL;
03463   return mol->get_component_name(repid);
03464 }
03465 
03466 int VMDApp::molrep_get_by_name(int molid, const char *name) {
03467   Molecule *mol = moleculeList->mol_from_id(molid);  
03468   if (!mol) return -1;
03469   return mol->get_component_by_name(name);
03470 }
03471 
03472 int VMDApp::molrep_get_scaleminmax(int molid, int repid, float *min, float *max) {
03473   if (repid < 0 || repid >= num_molreps(molid)) return FALSE;
03474   const DrawMolItem *item = moleculeList->mol_from_id(molid)->component(repid);
03475 #if 0
03476   // XXX Axel's color data range auto scale patch to fix the "two clicks"
03477   // problem he discovered with some volumetric datasets.  Needs closer
03478   // examination when I have a few minutes, but this will get him by for
03479   // the CPMD tutorial.
03480   Molecule *mol = moleculeList->mol_from_id(molid);
03481   item->atomColor->rescale_colorscale_minmax();
03482   item->atomColor->find(mol);
03483 #endif
03484   item->atomColor->get_colorscale_minmax(min, max);
03485   return TRUE;
03486 }
03487 int VMDApp::molrep_set_scaleminmax(int molid, int repid, float min, float max) {
03488   if (repid < 0 || repid >= num_molreps(molid)) return FALSE;
03489   DrawMolItem *item = moleculeList->mol_from_id(molid)->component(repid);
03490   if (item->atomColor->set_colorscale_minmax(min, max)) {
03491     item->force_recalc(DrawMolItem::COL_REGEN);
03492     commandQueue->runcommand(new CmdMolScaleMinmax(molid, repid, min, max));
03493     return TRUE;
03494   }
03495   return FALSE;
03496 }
03497 int VMDApp::molrep_reset_scaleminmax(int molid, int repid) {
03498   if (repid < 0 || repid >= num_molreps(molid)) return FALSE;
03499   DrawMolItem *item = moleculeList->mol_from_id(molid)->component(repid);
03500   item->atomColor->rescale_colorscale_minmax();
03501   item->force_recalc(DrawMolItem::COL_REGEN);
03502   commandQueue->runcommand(new CmdMolScaleMinmax(molid, repid, 0, 0, 1));
03503   return TRUE;
03504 }
03505 
03506 int VMDApp::molrep_set_drawframes(int molid, int repid, const char *framesel) {
03507   if (repid < 0 || repid >= num_molreps(molid)) return FALSE;
03508   if (!framesel) {
03509     msgErr << "molrep_set_drawframes: Error, framesel is NULL!" << sendmsg;
03510     return FALSE;
03511   }
03512   DrawMolItem *item = moleculeList->mol_from_id(molid)->component(repid);
03513   item->set_drawframes(framesel);
03514   commandQueue->runcommand(new CmdMolDrawFrames(molid, repid, framesel));
03515   return TRUE;
03516 }
03517 
03518 const char *VMDApp::molrep_get_drawframes(int molid, int repid) {
03519   if (repid < 0 || repid >= num_molreps(molid)) return NULL;
03520   const DrawMolItem *item = moleculeList->mol_from_id(molid)->component(repid);
03521   return item->get_drawframes();
03522 }
03523 
03524 int VMDApp::molrep_show(int molid, int repid, int onoff) {
03525   if (repid < 0 || repid >= num_molreps(molid)) return FALSE;
03526   moleculeList->mol_from_id(molid)->show_rep(repid, onoff);
03527   commandQueue->runcommand(new CmdMolShowRep(molid, repid, onoff));
03528   return TRUE;
03529 }
03530 
03531 int VMDApp::molrep_is_shown(int molid, int repid) {
03532   if (repid < 0 || repid >= num_molreps(molid)) return FALSE;
03533   DrawMolItem *item = moleculeList->mol_from_id(molid)->component(repid);
03534   return item->displayed();
03535 }
03536 
03537 
03538 //
03539 // IMD methods
03540 //
03541 int VMDApp::imd_connect(int molid, const char *host, int port) {
03542 #ifdef VMDIMD 
03543   Molecule *mol = moleculeList->mol_from_id(molid);  
03544   if (!mol) return 0;
03545   if (!imdMgr) return 0;
03546   if (imdMgr->connect(mol, host, port)) {
03547     // tell the world
03548     commandQueue->runcommand(new CmdIMDConnect(molid,host, port));
03549     return 1;
03550   }
03551 #endif
03552   return 0;
03553 }
03554 
03555 int VMDApp::imd_connected(int molid) {
03556 #ifdef VMDIMD
03557   if (!imdMgr) return 0;
03558   Molecule *mol = imdMgr->get_imdmol();
03559   if (mol) {
03560     return (mol->id() == molid);
03561   }
03562 #endif
03563   return 0;
03564 }
03565 
03566 int VMDApp::imd_sendforces(int num, const int *ind, const float *forces) {
03567 #ifdef VMDIMD
03568   if (!imdMgr) 
03569     return 0;
03570 
03571   return imdMgr->send_forces(num, ind, forces);
03572 #else
03573   return 0;
03574 #endif
03575 }
03576 
03577 int VMDApp::imd_disconnect(int molid) {
03578 #ifdef VMDIMD
03579   if (!imdMgr) return FALSE;
03580   Molecule *mol  = imdMgr->get_imdmol();
03581   if (mol && mol->id() == molid) {
03582     imdMgr->detach();
03583     return TRUE;
03584   }
03585 #endif
03586   return FALSE;
03587 }
03588 
03589 
03590 //
03591 // VideoStream methods
03592 //
03593 int VMDApp::vs_connect(const char *host, int port) {
03594 #ifdef VMDNVPIPE
03595   if (!uivs) return 0;
03596   if (uivs->cli_connect(host, port)) {
03597     // tell the world
03598 //    commandQueue->runcommand(new CmdVSConnect(host, port));
03599 msgInfo << "VMDApp: VideoStream connected" << sendmsg;
03600     return 1;
03601   }
03602 #endif
03603   return 0;
03604 }
03605 
03606 int VMDApp::vs_connected() {
03607 #ifdef VMDNVPIPE
03608   if (!uivs) return 0;
03609   // XXX check for connection here
03610 #endif
03611   return 0;
03612 }
03613 
03614 int VMDApp::vs_disconnect() {
03615 #ifdef VMDNVPIPE
03616   if (!uivs) return FALSE;
03617   if (uivs) {
03618     uivs->cli_disconnect();
03619     return TRUE;
03620   }
03621 #endif
03622   return FALSE;
03623 }
03624 
03625 
03626 
03627 //
03628 // Display methods
03629 //
03630 
03631 void VMDApp::display_set_screen_height(float ht) {
03632   if (!display) return;
03633   display->screen_height(ht);
03634   commandQueue->runcommand(new CmdDisplayScreenHeight(ht));
03635 }
03636 float VMDApp::display_get_screen_height() {
03637   if (!display) return 0.0f;
03638   return display->screen_height();
03639 }
03640 void VMDApp::display_set_screen_distance(float d) {
03641   if (!display) return;
03642   display->distance_to_screen(d);
03643   commandQueue->runcommand(new CmdDisplayScreenDistance(d));
03644 }
03645 float VMDApp::display_get_screen_distance() {
03646   if (!display) return 0.0f;
03647   return display->distance_to_screen();
03648 }
03649 void VMDApp::display_set_position(int x, int y) {
03650   if (display)
03651     display->reposition_window(x, y);
03652 }
03653 #if 0
03654 void VMDApp::display_get_position(int *x, int *y) {
03655   if (display) {
03656     display->window_position(x, y);
03657   }
03658 }
03659 #endif
03660 void VMDApp::display_set_size(int w, int h) {
03661   if (display) {
03662     display->resize_window(w, h);
03663     // do an update so that the new size of the window becomes immediately
03664     // available.  
03665     display_update_ui();
03666   }
03667 }
03668 void VMDApp::display_get_size(int *w, int *h) {
03669   if (display) {
03670     *w = display->xSize;
03671     *h = display->ySize;
03672   }
03673 }
03674 void VMDApp::display_titlescreen() {
03675   if (display && display->supports_gui()) {
03676     delete vmdTitle;
03677     vmdTitle = new VMDTitle(display, &(scene->root));
03678   }
03679 }
03680 
03681 int VMDApp::display_set_stereo(const char *mode) {
03682   if (!mode) 
03683     return FALSE;
03684 
03685   int i, j;
03686   for (i=0; i<display->num_stereo_modes(); i++) {
03687     if (!strcmp(mode, display->stereo_name(i))) {
03688       display->set_stereo_mode(i);
03689       commandQueue->runcommand(new CmdDisplayStereo(mode));
03690       return TRUE;
03691     }
03692   }
03693 
03694   // Backwards compatibility with old scripts...
03695   const char *OldStereoNames[] = { 
03696     "CrystalEyes", "CrystalEyesReversed", "CrossEyes" 
03697   };
03698   const char *NewStereoNames[] = {
03699     "QuadBuffered", "QuadBuffered", "SideBySide" 
03700   };
03701   for (j=0; j<3; j++) {
03702     if (!strcmp(mode, OldStereoNames[j])) {
03703       for (i=0; i<display->num_stereo_modes(); i++) {
03704         if (!strcmp(NewStereoNames[j], display->stereo_name(i))) {
03705           display->set_stereo_mode(i);
03706           commandQueue->runcommand(new CmdDisplayStereo(NewStereoNames[j]));
03707 
03708           // preserve the swapped eye behavior of the old stereo mode names
03709           if (!strcmp(mode, "CrystalEyesReversed") ||
03710               !strcmp(mode, "CrossEyes")) {
03711             display_set_stereo_swap(1); 
03712           } 
03713           return TRUE;
03714         }
03715       }
03716     }
03717   }
03718 
03719   msgErr << "Illegal stereo mode: " << mode << sendmsg;
03720   return FALSE;
03721 }
03722 
03723 int VMDApp::display_set_stereo_swap(int onoff) {
03724   if (!onoff) {
03725     display->set_stereo_swap(0);
03726     commandQueue->runcommand(new CmdDisplayStereoSwap(0));
03727     return TRUE;
03728   }
03729 
03730   display->set_stereo_swap(1);
03731   commandQueue->runcommand(new CmdDisplayStereoSwap(1));
03732   return TRUE;
03733 }
03734 
03735 int VMDApp::display_set_cachemode(const char *mode) {
03736   if (!mode) return FALSE;
03737   for (int i=0; i<display->num_cache_modes(); i++) {
03738     if (!strcmp(mode, display->cache_name(i))) {
03739       display->set_cache_mode(i);
03740       commandQueue->runcommand(new CmdDisplayCacheMode(mode));
03741       return TRUE;
03742     }
03743   }
03744   msgErr << "Illegal cache mode: " << mode << sendmsg;
03745   return FALSE;
03746 }
03747 
03748 int VMDApp::display_set_rendermode(const char *mode) {
03749   if (!mode) return FALSE;
03750   for (int i=0; i<display->num_render_modes(); i++) {
03751     if (!strcmp(mode, display->render_name(i))) {
03752       display->set_render_mode(i);
03753       commandQueue->runcommand(new CmdDisplayRenderMode(mode));
03754       return TRUE;
03755     }
03756   }
03757   msgErr << "Illegal rendering mode: " << mode << sendmsg;
03758   return FALSE;
03759 }
03760 
03761 int VMDApp::display_set_eyesep(float sep) {
03762   if (sep < 0) return FALSE;
03763   display->set_eyesep(sep);
03764   commandQueue->runcommand(new CmdDisplayEyesep(sep));
03765   return TRUE;
03766 }
03767 
03768 int VMDApp::display_set_focallen(float flen) {
03769   if (!display->set_eye_dist(flen)) return FALSE;
03770   commandQueue->runcommand(new CmdDisplayFocallen(flen));
03771   return TRUE;
03772 }
03773 
03774 int VMDApp::display_set_projection(const char *proj) {
03775   if (!display->set_projection(proj)) return FALSE;
03776   commandQueue->runcommand(new CmdDisplayProj(proj));
03777   return TRUE;
03778 }
03779 
03780 int VMDApp::display_projection_is_perspective(void) {
03781   if (display->projection() == DisplayDevice::ORTHOGRAPHIC)
03782     return FALSE;
03783 
03784   return TRUE;
03785 }
03786 
03787 int VMDApp::display_set_aa(int onoff) {
03788   if (!display->aa_available()) return FALSE;
03789   if (onoff) display->aa_on(); else display->aa_off();
03790   commandQueue->runcommand(new CmdDisplayAAOn(onoff));
03791   return TRUE;
03792 }
03793 
03794 int VMDApp::display_set_depthcue(int onoff) {
03795   if (!display->cueing_available()) return FALSE;
03796   if (onoff) display->cueing_on(); else display->cueing_off();
03797   commandQueue->runcommand(new CmdDisplayDepthcueOn(onoff));
03798   return TRUE;
03799 }
03800 
03801 int VMDApp::display_set_culling(int onoff) {
03802   if (!display->culling_available()) return FALSE;
03803   if (onoff) display->culling_on(); else display->culling_off();
03804   commandQueue->runcommand(new CmdDisplayCullingOn(onoff));
03805   return TRUE;
03806 }
03807 
03808 int VMDApp::display_set_fps(int onoff) {
03809   if (onoff) fps->on(); else fps->off();
03810   commandQueue->runcommand(new CmdDisplayFPSOn(onoff));
03811   return TRUE;
03812 }
03813 
03814 int VMDApp::display_set_background_mode(int mode) {
03815   scene->set_background_mode(mode);
03816   commandQueue->runcommand(new CmdDisplayBackgroundGradientOn(mode));
03817   return TRUE;
03818 }
03819 
03820 int VMDApp::display_set_nearclip(float amt, int isdelta) {
03821   if (isdelta) {
03822     display->addto_near_clip(amt); 
03823     commandQueue->runcommand(new CmdDisplayClipNearRel(amt));
03824   } else {
03825     // prevent illegal near clipping plane values from causing problems
03826     if (amt <= 0.0)
03827       amt = 0.001f;
03828     display->set_near_clip(amt);
03829     commandQueue->runcommand(new CmdDisplayClipNear(amt));
03830   }
03831   return TRUE;
03832 }
03833 
03834 int VMDApp::display_set_farclip(float amt, int isdelta) {
03835   if (isdelta) {
03836     display->addto_far_clip(amt); 
03837     commandQueue->runcommand(new CmdDisplayClipFarRel(amt));
03838   } else {
03839     display->set_far_clip(amt);
03840     commandQueue->runcommand(new CmdDisplayClipFar(amt));
03841   }
03842   return TRUE;
03843 }
03844 
03845 int VMDApp::stage_set_location (const char *pos) {
03846   if (!pos) return FALSE;
03847   for (int i=0; i<stage->locations(); i++) {
03848     if (!strupcmp(pos, stage->loc_description(i))) {
03849       stage->location(i);
03850       commandQueue->runcommand(new CmdDisplayStageLocation(pos));
03851       return TRUE;
03852     }
03853   }
03854   return FALSE;
03855 }
03856 
03857 int VMDApp::stage_set_numpanels(int num) {
03858   if (!stage->panels(num)) return FALSE;
03859   commandQueue->runcommand(new CmdDisplayStagePanels(num));
03860   return TRUE;
03861 }
03862 
03863 int VMDApp::stage_set_size(float sz) {
03864   if (!stage->size(sz)) return FALSE;
03865   commandQueue->runcommand(new CmdDisplayStageSize(sz));
03866   return TRUE;
03867 }
03868 
03869 int VMDApp::axes_set_location (const char *pos) {
03870   if (!pos) return FALSE;
03871   for (int i=0; i<axes->locations(); i++) {
03872     if (!strupcmp(pos, axes->loc_description(i))) {
03873       axes->location(i);
03874       commandQueue->runcommand(new CmdDisplayAxes(pos));
03875       return TRUE;
03876     }
03877   }
03878   return FALSE;
03879 }
03880 
03881 int VMDApp::light_on(int n, int onoff) {
03882   if (n<0 || n >= DISP_LIGHTS) return FALSE;
03883   scene->activate_light(n, onoff);
03884   commandQueue->runcommand(new CmdDisplayLightOn(n, onoff));
03885   return TRUE;
03886 }
03887 int VMDApp::light_highlight(int n, int onoff) {
03888   if (n<0 || n >= DISP_LIGHTS) return FALSE;
03889   scene->highlight_light(n, onoff);
03890   commandQueue->runcommand(new CmdDisplayLightHL(n, onoff));
03891   return TRUE;
03892 }
03893 
03894 int VMDApp::light_rotate(int n, float amt, char axis) {
03895   if (n<0 || n >= DISP_LIGHTS) return FALSE;
03896   scene->rotate_light(n, amt, axis);
03897   commandQueue->runcommand(new CmdDisplayLightRot(n, amt, axis));
03898   return TRUE;
03899 }
03900 
03901 int VMDApp::light_move(int n, const float *newpos) {
03902   if (n<0 || n >= DISP_LIGHTS) return FALSE;
03903   scene->move_light(n, newpos);
03904   commandQueue->runcommand(new CmdDisplayLightMove(n, newpos));
03905   return TRUE;
03906 }
03907 
03908 int VMDApp::depthcue_set_mode(const char *mode) {
03909   if (!display->set_cue_mode(mode)) return FALSE;
03910   commandQueue->runcommand(new CmdDisplayCueMode(mode));
03911   return TRUE;
03912 }
03913 
03914 int VMDApp::depthcue_set_start(float val) {
03915   if (!display->set_cue_start(val)) return FALSE;
03916   commandQueue->runcommand(new CmdDisplayCueStart(val));
03917   return TRUE;
03918 }
03919 
03920 int VMDApp::depthcue_set_end(float val) {
03921   if (!display->set_cue_end(val)) return FALSE;
03922   commandQueue->runcommand(new CmdDisplayCueEnd(val));
03923   return TRUE;
03924 }
03925 
03926 int VMDApp::depthcue_set_density(float val) {
03927   if (!display->set_cue_density(val)) return FALSE;
03928   commandQueue->runcommand(new CmdDisplayCueDensity(val));
03929   return TRUE;
03930 }
03931 
03932 int VMDApp::display_set_shadows(int onoff) {
03933   if (!display->set_shadow_mode(onoff)) return FALSE;
03934   commandQueue->runcommand(new CmdDisplayShadowOn(onoff));
03935   return TRUE;
03936 } 
03937 
03938 int VMDApp::display_set_ao(int onoff) {
03939   if (!display->set_ao_mode(onoff)) return FALSE;
03940   commandQueue->runcommand(new CmdDisplayAOOn(onoff));
03941   return TRUE;
03942 } 
03943 
03944 int VMDApp::display_set_ao_ambient(float val) {
03945   if (!display->set_ao_ambient(val)) return FALSE;
03946   commandQueue->runcommand(new CmdDisplayAOAmbient(val));
03947   return TRUE;
03948 }
03949 
03950 int VMDApp::display_set_ao_direct(float val) {
03951   if (!display->set_ao_direct(val)) return FALSE;
03952   commandQueue->runcommand(new CmdDisplayAODirect(val));
03953   return TRUE;
03954 }
03955 
03956 int VMDApp::display_set_dof(int onoff) {
03957   if (!display->set_dof_mode(onoff)) return FALSE;
03958   commandQueue->runcommand(new CmdDisplayDoFOn(onoff));
03959   return TRUE;
03960 } 
03961 
03962 int VMDApp::display_set_dof_fnumber(float f) {
03963   if (!display->set_dof_fnumber(f)) return FALSE;
03964   commandQueue->runcommand(new CmdDisplayDoFFNumber(f));
03965   return TRUE;
03966 }
03967 
03968 int VMDApp::display_set_dof_focal_dist(float d) {
03969   if (!display->set_dof_focal_dist(d)) return FALSE;
03970   commandQueue->runcommand(new CmdDisplayDoFFocalDist(d));
03971   return TRUE;
03972 }
03973 
03974 void VMDApp::deactivate_uitext_stdin() {
03975   if (uiText)
03976     uiText->Off();
03977 }
03978 
03979 int VMDApp::activate_menus() {
03980   // XXX This should control Tk menus as well; at present Tk menus are 
03981   // available whenever the display supports GUI's.
03982 
03983 #ifdef VMDGUI
03984   if(display->supports_gui()) {
03985 
03986     delete uivr;
03987     uivr = new UIVR(this);
03988     uivr->On();
03989 
03990     // if we are using the FLTK library ...
03991 #ifdef VMDFLTK
03992   VMDMenu *obj;
03993   obj = new MainFltkMenu(this);
03994   menulist->add_name(obj->get_name(), obj);
03995   obj = new ColorFltkMenu(this);
03996   menulist->add_name(obj->get_name(), obj);
03997   obj = new MaterialFltkMenu(this);
03998   menulist->add_name(obj->get_name(), obj);
03999   obj = new DisplayFltkMenu(this);
04000   menulist->add_name(obj->get_name(), obj);
04001   obj = new FileChooserFltkMenu(this);
04002   menulist->add_name(obj->get_name(), obj);
04003   obj = new GeometryFltkMenu(this);
04004   menulist->add_name(obj->get_name(), obj);
04005   obj = new GraphicsFltkMenu(this);
04006   menulist->add_name(obj->get_name(), obj);
04007   obj = new RenderFltkMenu(this);
04008   menulist->add_name(obj->get_name(), obj);
04009   obj = new SaveTrajectoryFltkMenu(this);
04010   menulist->add_name(obj->get_name(), obj);
04011   obj = new ToolFltkMenu(this);
04012   menulist->add_name(obj->get_name(), obj);
04013 #endif /*VMDFLTK*/
04014   }
04015   return TRUE;
04016 #endif /*VMDGUI*/
04017   
04018   // no menus available
04019   return FALSE;
04020 }
04021 
04022 int VMDApp::label_add(const char *category, int n, const int *molids, 
04023     const int *atomids, const int *cells, float k, int toggle) {
04024   if (!category || !molids || !atomids) return -1;
04025   int rc = geometryList->add_geometry(category, molids, atomids, cells, k, 
04026       toggle);
04027   if (rc >= 0) {
04028     if (!strcmp(category, "Springs"))
04029       commandQueue->runcommand(new CmdLabelAddspring(molids[0], atomids[0],
04030           atomids[1], k));
04031     else 
04032       commandQueue->runcommand(new CmdLabelAdd(category, n, (int *)molids, (int *)atomids));
04033   }
04034   return rc;
04035 }
04036 
04037 int VMDApp::label_show (const char *category, int n, int onoff) {
04038   if (!category) return FALSE;
04039   if (geometryList->show_geometry(category, n, onoff)) {
04040     commandQueue->runcommand(new CmdLabelShow(category, n, onoff));
04041     return TRUE;
04042   }
04043   return FALSE;
04044 }
04045 
04046 float VMDApp::label_get_text_size() const {
04047   return geometryList->getTextSize();
04048 }
04049 
04050 int VMDApp::label_set_text_size(float newsize) {
04051   if (geometryList->setTextSize(newsize)) {
04052     commandQueue->runcommand(new CmdLabelTextSize(newsize));
04053     return TRUE;
04054   }
04055   return FALSE;
04056 }
04057 
04058 float VMDApp::label_get_text_thickness() const {
04059   return geometryList->getTextThickness();
04060 }
04061 
04062 int VMDApp::label_set_text_thickness(float newthick) {
04063   if (geometryList->setTextThickness(newthick)) {
04064     commandQueue->runcommand(new CmdLabelTextThickness(newthick));
04065     return TRUE;
04066   }
04067   return FALSE;
04068 }
04069 
04070 int VMDApp::label_set_textoffset(const char *nm, int n, float x, float y) {
04071   float delta[2] = { x, y };
04072   if (geometryList->setTextOffset(nm, n, delta)) {
04073     commandQueue->runcommand(new CmdLabelTextOffset(nm, n, x, y));
04074     return TRUE;
04075   }
04076   return FALSE;
04077 }
04078 
04079 int VMDApp::label_set_textformat(const char *nm, int n, const char *format) {
04080   if (geometryList->setTextFormat(nm, n, format)) {
04081     commandQueue->runcommand(new CmdLabelTextFormat(nm, n, format));
04082     return TRUE;
04083   }
04084   return FALSE;
04085 }
04086 
04087 int VMDApp::label_delete(const char *category, int n) {
04088   if (!category) return FALSE;
04089   if (geometryList->del_geometry(category, n)) {
04090     commandQueue->runcommand(new CmdLabelDelete(category, n));
04091     return TRUE;
04092   }
04093   return FALSE;
04094 }
04095 
04096 int VMDApp::tool_create(const char *type, int argc, const char **argv) {
04097   if (!uivr) return FALSE;
04098   if (!uivr->add_tool_with_USL(type, argc, argv)) return FALSE;
04099   commandQueue->runcommand(new CmdToolCreate(type, argc, argv));
04100   return TRUE;
04101 }
04102 
04103 int VMDApp::tool_change_type(int toolnum, const char *type) {
04104   if (!uivr) return FALSE;
04105   if (!uivr->change_type(toolnum, type)) return FALSE;
04106   commandQueue->runcommand(new CmdToolChange(type, toolnum));
04107   return TRUE;
04108 }
04109 
04110 int VMDApp::tool_delete(int toolnum) {
04111   if (!uivr) return FALSE;
04112   if (!uivr->remove_tool(toolnum)) return FALSE;
04113   commandQueue->runcommand(new CmdToolDelete(toolnum));
04114   // XXXX fix this for multiple tools
04115   commandQueue->runcommand(new PickAtomCallbackEvent(-1,-1,"uivr"));
04116   return TRUE;
04117 }
04118 
04119 int VMDApp::tool_set_position_scale(int toolnum, float newval) {
04120   if (!uivr) return FALSE;
04121   if (uivr->set_position_scale(toolnum, newval)) {
04122     commandQueue->runcommand(new CmdToolScale(newval, toolnum));
04123     return TRUE;
04124   }
04125   return FALSE;
04126 }
04127 
04128 int VMDApp::tool_set_force_scale(int toolnum, float newval) {
04129   if (!uivr) return FALSE;
04130   if (uivr->set_force_scale(toolnum, newval)) {
04131     commandQueue->runcommand(new CmdToolScaleForce(newval, toolnum));
04132     return TRUE;
04133   }
04134   return FALSE;
04135 }
04136 
04137 int VMDApp::tool_set_spring_scale(int toolnum, float newval) {
04138   if (!uivr) return FALSE;
04139   if (uivr->set_spring_scale(toolnum, newval)) {
04140     commandQueue->runcommand(new CmdToolScaleSpring(newval, toolnum));
04141     return TRUE;
04142   }
04143   return FALSE;
04144 }
04145 
04146 const char *VMDApp::material_add(const char *name, const char *copy) {
04147   const char *newname = materialList->add_material(name, copy);
04148   if (newname) {
04149     commandQueue->runcommand(new CmdMaterialAdd(name, copy));
04150   }
04151   return newname;
04152 }
04153 
04154 int VMDApp::material_delete(const char *name) {
04155   char * strname = stringdup(name);
04156   int ind = materialList->material_index(strname);
04157   if (materialList->delete_material(ind)) {
04158     commandQueue->runcommand(new CmdMaterialDelete(strname));
04159     delete [] strname;
04160     return TRUE;
04161   }
04162   delete [] strname;
04163   return FALSE;
04164 }
04165 
04166 int VMDApp::material_rename(const char *prevname, const char *newname) {
04167   char * oldname = stringdup(prevname);
04168   int ind = materialList->material_index(oldname);
04169   if (ind < 0) {
04170     msgErr << "material rename: '" << oldname << "' does not exist."   
04171            << sendmsg;
04172     delete [] oldname;
04173     return FALSE;
04174   }
04175   int n = strlen(newname);
04176   if (!n) return FALSE;
04177   for (size_t i=0; i<strlen(newname); i++) {
04178     if (!isalnum(newname[i])) {
04179       msgErr << "material rename: new name contains non-alphanumeric character"
04180              << sendmsg;
04181       delete [] oldname;
04182       return FALSE;
04183     }
04184   }
04185   if (materialList->material_index(newname) >= 0) {
04186     msgErr << "material rename: '" << newname << "' already exists." 
04187            << sendmsg;
04188     delete [] oldname;
04189     return FALSE;
04190   }
04191   materialList->set_name(ind, newname);
04192   commandQueue->runcommand(new CmdMaterialRename(oldname, newname));
04193   delete [] oldname;
04194   return TRUE;
04195 }
04196 
04197 int VMDApp::material_change(const char *name, int property, float val) {
04198   int ind = materialList->material_index(name);
04199   if (ind < 0) return FALSE;
04200   switch (property) {
04201     case MAT_AMBIENT: materialList->set_ambient(ind, val); break;
04202     case MAT_SPECULAR: materialList->set_specular(ind, val); break;
04203     case MAT_DIFFUSE: materialList->set_diffuse(ind, val); break;
04204     case MAT_SHININESS: materialList->set_shininess(ind, val); break;
04205     case MAT_MIRROR: materialList->set_mirror(ind, val); break;
04206     case MAT_OPACITY: materialList->set_opacity(ind, val); break;
04207     case MAT_OUTLINE: materialList->set_outline(ind, val); break;
04208     case MAT_OUTLINEWIDTH: materialList->set_outlinewidth(ind, val); break;
04209     case MAT_TRANSMODE: materialList->set_transmode(ind, val); break;
04210   }
04211   commandQueue->runcommand(new CmdMaterialChange(name, property, val));
04212   return TRUE;
04213 }
04214 
04215 int VMDApp::material_restore_default(int ind) {
04216   if (materialList->restore_default(ind)) {
04217     commandQueue->runcommand(new CmdMaterialDefault(ind));
04218     return TRUE;
04219   }
04220   return FALSE;
04221 }
04222 
04223 int VMDApp::mouse_set_mode(int mm, int ms) {
04224   if (!mouse->move_mode((Mouse::MoveMode)mm, ms)) {
04225     msgErr << "Illegal mouse mode: " << mm << " " << ms << sendmsg;
04226     return FALSE;
04227   }
04228   
04229   // If mouse mode is a picking mode, set it here
04230   switch (mm) {
04231     case Mouse::PICK:        pickModeList->set_pick_mode(PickModeList::PICK); break;
04232     case Mouse::QUERY:       pickModeList->set_pick_mode(PickModeList::QUERY); break;
04233     case Mouse::CENTER:      pickModeList->set_pick_mode(PickModeList::CENTER); break;
04234     case Mouse::LABELATOM:   pickModeList->set_pick_mode(PickModeList::LABELATOM); break;
04235     case Mouse::LABELBOND:   pickModeList->set_pick_mode(PickModeList::LABELBOND); break;
04236     case Mouse::LABELANGLE:  pickModeList->set_pick_mode(PickModeList::LABELANGLE); break;
04237     case Mouse::LABELDIHEDRAL:  pickModeList->set_pick_mode(PickModeList::LABELDIHEDRAL); break;
04238     case Mouse::MOVEATOM:    pickModeList->set_pick_mode(PickModeList::MOVEATOM); break;
04239     case Mouse::MOVERES:     pickModeList->set_pick_mode(PickModeList::MOVERES); break;
04240     case Mouse::MOVEFRAG:    pickModeList->set_pick_mode(PickModeList::MOVEFRAG); break;
04241     case Mouse::MOVEMOL:     pickModeList->set_pick_mode(PickModeList::MOVEMOL); break;
04242     case Mouse::FORCEATOM:   pickModeList->set_pick_mode(PickModeList::FORCEATOM); break;
04243     case Mouse::FORCERES:    pickModeList->set_pick_mode(PickModeList::FORCERES); break;
04244     case Mouse::FORCEFRAG:   pickModeList->set_pick_mode(PickModeList::FORCEFRAG); break;
04245     case Mouse::MOVEREP:     pickModeList->set_pick_mode(PickModeList::MOVEREP); break;
04246     case Mouse::ADDBOND:     pickModeList->set_pick_mode(PickModeList::ADDBOND); break;
04247     default: break;
04248   }
04249   
04250   commandQueue->runcommand(new CmdMouseMode(mm, ms));
04251   return TRUE;
04252 }
04253 
04254 
04255 int VMDApp::mobile_set_mode(int mm) {
04256   if (!mobile->move_mode((Mobile::MoveMode) mm)) {
04257     msgErr << "Illegal mobile mode: " << mm << " " << sendmsg;
04258     return FALSE;
04259   }
04260   commandQueue->runcommand(new CmdMobileMode(mm));
04261   return TRUE;
04262 }
04263 
04264 int VMDApp::mobile_get_mode() {
04265   return mobile->get_move_mode();
04266 }
04267 
04268 void VMDApp::mobile_get_client_list(ResizeArray <JString*>* &nick, 
04269                          ResizeArray <JString*>* &ip, ResizeArray <bool>* &active) 
04270 {
04271   mobile->get_client_list(nick, ip, active);
04272 }
04273 
04274 int VMDApp::mobile_network_port(int port) {
04275   mobile->network_port(port);
04276   //  commandQueue->runcommand(new CmdMobileNetworkPort(port));
04277   return TRUE;
04278 }
04279 
04280 int VMDApp::mobile_get_network_port() {
04281   return mobile->get_port();
04282 }
04283 
04284 int VMDApp::mobile_get_APIsupported() {
04285   return mobile->get_APIsupported();
04286 }
04287 
04289 int VMDApp::mobile_set_activeClient(const char *nick, const char *ip) {
04290   return mobile->set_activeClient(nick, ip);
04291 }
04292 
04294 int VMDApp::mobile_sendMsg(const char *nick, const char *ip, 
04295                            const char *msgType, const char *msg) {
04296   return mobile->sendMsgToClient(nick, ip, msgType, msg);
04297 }
04298 
04299 
04302 void VMDApp::mobile_get_tracker_status(float &tx, float &ty, float &tz,
04303                                        float &rx, float &ry, float &rz,
04304                                        int &buttons) {
04305   if (mobile != NULL) {
04306     mobile->get_tracker_status(tx, ty, tz, rx, ry, rz, buttons);
04307   } else {
04308     tx=ty=tz=rx=ry=rz=0.0f;
04309     buttons=0;
04310   }
04311 }
04312 
04313 
04314 int VMDApp::spaceball_set_mode(int mm) {
04315   if (!spaceball->move_mode((Spaceball::MoveMode) mm)) {
04316     msgErr << "Illegal spaceball mode: " << mm << " " << sendmsg;
04317     return FALSE;
04318   }
04319   commandQueue->runcommand(new CmdSpaceballMode(mm));
04320   return TRUE;
04321 }
04322 
04323 
04324 int VMDApp::spaceball_set_sensitivity(float s) {
04325   spaceball->set_sensitivity(s);
04326   //  commandQueue->runcommand(new CmdSpaceballSensitivity(s));
04327   return TRUE;
04328 }
04329 
04330 
04331 int VMDApp::spaceball_set_null_region(int nr) {
04332   spaceball->set_null_region(nr);
04333   //  commandQueue->runcommand(new CmdSpaceballNullRegion(s));
04334   return TRUE;
04335 }
04336 
04337 
04340 void VMDApp::spaceball_get_tracker_status(float &tx, float &ty, float &tz,
04341                                           float &rx, float &ry, float &rz,
04342                                           int &buttons) {
04343   if (spaceball != NULL) {
04344     spaceball->get_tracker_status(tx, ty, tz, rx, ry, rz, buttons);
04345   } else {
04346     tx=ty=tz=rx=ry=rz=0.0f;
04347     buttons=0;
04348   }
04349 }
04350 
04351 
04352 int VMDApp::textinterp_change(const char *name) {
04353   return uiText->change_interp(name);
04354 }
04355 
04356 //
04357 // MPI related routines
04358 //
04359 void VMDApp::par_barrier() {
04360 #if defined(VMDMPI)
04361   // perform a barrier if running in parallel
04362   if (mpienabled)
04363     vmd_mpi_barrier();
04364 #endif
04365 }
04366 

Generated on Fri Oct 4 02:45:11 2024 for VMD (current) by doxygen1.2.14 written by Dimitri van Heesch, © 1997-2002