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