00001 /*************************************************************************** 00002 *cr 00003 *cr (C) Copyright 1995-2019 The Board of Trustees of the 00004 *cr University of Illinois 00005 *cr All Rights Reserved 00006 *cr 00007 ***************************************************************************/ 00008 00009 /*************************************************************************** 00010 * RCS INFORMATION: 00011 * 00012 * $RCSfile: FileRenderList.C,v $ 00013 * $Author: johns $ $Locker: $ $State: Exp $ 00014 * $Revision: 1.111 $ $Date: 2021年12月13日 07:54:00 $ 00015 * 00016 *************************************************************************** 00017 * DESCRIPTION: 00018 * 00019 * The FileRenderList class maintains a list of available FileRenderer 00020 * objects 00021 * 00022 ***************************************************************************/ 00023 00024 #include "config.h" // create dependency so new compile options cause rebuild 00025 #include "FileRenderList.h" 00026 #include "VMDApp.h" 00027 #include "CmdRender.h" 00028 #include "CommandQueue.h" 00029 #include "Scene.h" 00030 #include "DisplayDevice.h" 00031 #include "TextEvent.h" 00032 #include "Inform.h" 00033 #include "WKFThreads.h" // CPU capability flags 00034 #include <stdlib.h> // for system() 00035 00036 // 00037 // Supported external rendering programs 00038 // 00039 #if defined(VMDLIBANARI) 00040 #include "ANARIDisplayDevice.h" // ANARI sci-vis rendering API 00041 #endif 00042 #include "ArtDisplayDevice.h" // Art ray tracer 00043 #include "GelatoDisplayDevice.h" // nVidia Gelato 00044 #if defined(VMDLIBOPTIX) 00045 // We include the OptiX related headers first to prevent collisions between 00046 // enums in OptiXRenderer, and preprocessor macros in Tachyon... 00047 #include "OptiXDisplayDevice.h" // Compiled-in OptiX ray tracer 00048 #endif 00049 #if defined(VMDLIBOSPRAY) 00050 #include "OSPRayDisplayDevice.h" // Compiled-in OSPRay 1.x ray tracer 00051 #endif 00052 #if defined(VMDLIBOSPRAY2) 00053 #include "OSPRay2DisplayDevice.h" // Compiled-in OSPRay 2.x ray tracer 00054 #endif 00055 #if defined(VMDLIBTACHYON) 00056 #include "LibTachyonDisplayDevice.h" // Compiled-in Tachyon ray tracer 00057 #endif 00058 #if defined(VMDLIBGELATO) 00059 #include "LibGelatoDisplayDevice.h" // Compiled-in Gelato renderer 00060 #endif 00061 #include "MayaDisplayDevice.h" // Autodesk Maya 00062 #include "POV3DisplayDevice.h" // POVRay 3.x 00063 #include "PSDisplayDevice.h" // Postscript 00064 #include "R3dDisplayDevice.h" // Raster3D 00065 #include "RadianceDisplayDevice.h" // Radiance, unknown version 00066 #include "RayShadeDisplayDevice.h" // Rayshade 4.0 00067 #include "RenderManDisplayDevice.h" // RenderMan interface 00068 #include "SnapshotDisplayDevice.h" // Built-in snapshot capability 00069 #include "STLDisplayDevice.h" // Stereolithography files 00070 #include "TachyonDisplayDevice.h" // Tachyon ray tracer 00071 #include "VrmlDisplayDevice.h" // VRML 1.0 00072 #include "Vrml2DisplayDevice.h" // VRML 2.0 / VRML97 00073 #include "WavefrontDisplayDevice.h" // Wavefront "OBJ" files 00074 #include "X3DDisplayDevice.h" // X3D (XML encoding) 00075 00076 00077 // constructor, start off with the default means of rendering 00078 FileRenderList::FileRenderList(VMDApp *vmdapp) : app(vmdapp) { 00079 00080 #if defined(VMDLIBOSPRAY) || defined(VMDLIBOSPRAY2) 00081 // check CPU instruction set capabilities for SSE 4.1 required by OSPRay 00082 wkf_cpu_caps_t cpucaps; 00083 int havecpucaps=0; 00084 if (!wkf_cpu_capability_flags(&cpucaps)) { 00085 havecpucaps=1; 00086 } 00087 #endif 00088 00089 add(new ArtDisplayDevice()); 00090 add(new GelatoDisplayDevice()); 00091 #if defined(VMDLIBGELATO) 00092 // Only add the internally linked gelato display device to the 00093 // menu if the user has correctly set the GELATOHOME environment 00094 // variable. If we allow them to use it otherwise, it may lead 00095 // to crashing, or failed renders. This way they won't even see it 00096 // as an option unless they've got Gelato installed and the environment 00097 // at least minimally configured. 00098 if (getenv("GELATOHOME") != NULL) { 00099 add(new LibGelatoDisplayDevice()); 00100 } 00101 #endif 00102 // XXX until the native Maya ASCII export code is finished, 00103 // only show it when a magic environment variable is set. 00104 if (getenv("VMDENABLEMAYA") != NULL) { 00105 add(new MayaDisplayDevice()); 00106 } 00107 add(new PSDisplayDevice()); 00108 add(new R3dDisplayDevice()); 00109 add(new RadianceDisplayDevice()); 00110 add(new RayShadeDisplayDevice()); 00111 add(new RenderManDisplayDevice()); 00112 add(new SnapshotDisplayDevice(app->display)); 00113 add(new STLDisplayDevice()); 00114 add(new TachyonDisplayDevice()); 00115 #if defined(VMDLIBTACHYON) 00116 add(new LibTachyonDisplayDevice(vmdapp)); 00117 #endif 00118 00119 00120 #if defined(VMDLIBANARI) 00121 // XXX ANARI initialization must precede OptiX 6.x to prevent 00122 // conflicts with OpenGL/EGL context creation in GL-based 00123 // renderer back-ends performed within the main VMD thread. 00124 // This issue will be resolved by OptiX 7.x 00125 if (!getenv("VMDNOANARI")) { 00126 ANARIDisplayDevice::ANARI_Global_Init(); // call only ONCE 00127 if (!getenv("VMDNOANARIBATCH")) { 00128 add(new ANARIDisplayDevice(vmdapp, 0)); 00129 } 00130 00131 #if !defined(__APPLE__) 00132 // XXX Since the glwin code hasn't yet been adapted to wrap FLTK, SDL, 00133 // or Apple-native Aqua/Cocoa, we can't enable the interactive RT window yet 00134 #if defined(VMDOPENGL) && defined(VMDANARI_INTERACTIVE_OPENGL) 00135 if (!getenv("VMDNOANARIINTERACTIVE") && !getenv("VMDANARIUSD")) { 00136 add(new ANARIDisplayDevice(vmdapp, 1)); 00137 } 00138 #endif 00139 #endif 00140 } 00141 #endif 00142 00143 00144 #if defined(VMDLIBOPTIX) 00145 if (!getenv("VMDNOOPTIX")) { 00146 int optixdevcount=OptiXDisplayDevice::device_count(); 00147 00148 // Only emit detailed OptiX GPU data if we're running on a single node. 00149 // Put the console informational text immediately prior to the creation of 00150 // FileRenderList objects where the renderers are actually instantiated, 00151 // so that all of the OptiX GPU and compilation status info is together 00152 if (vmdapp->nodecount == 1) { 00153 if (optixdevcount > 0) { 00154 msgInfo << "Detected " << optixdevcount << " available TachyonL/OptiX ray tracing " 00155 << ((optixdevcount > 1) ? "accelerators" : "accelerator") 00156 << sendmsg; 00157 } 00158 } 00159 00160 // Perform runtime check for OptiX availability before we add it to the 00161 // list of available renderers. 00162 if (optixdevcount > 0) { 00163 // Emit a console message during OptiX renderer instantiation 00164 // since the JIT compilation and linkage of the 256+ shaders may 00165 // take several seconds on machines with several GPUs... 00166 if (vmdapp->nodecount == 1) { 00167 msgInfo << " Compiling " 00168 // << OptiXRenderer::material_shader_table_size() 00169 << " OptiX shaders on " << optixdevcount << " target GPU" 00170 << ((optixdevcount > 1) ? "s" : "") << "..." << sendmsg; 00171 } 00172 00173 add(new OptiXDisplayDevice(vmdapp, 0)); 00174 00175 // Even if we have no GUI, then we now add interactive renderer 00176 // to be able to support remote rendering via video streaming 00177 // from clusters, supercomputers, etc. The renderer launch code 00178 // will determine whether or not to launch a GUI-based interactive 00179 // renderer or a renderer intended solely for video streaming. 00180 add(new OptiXDisplayDevice(vmdapp, 1)); 00181 } 00182 } 00183 #endif 00184 00185 #if defined(VMDLIBOSPRAY) || defined(VMDLIBOSPRAY2) 00186 if (!getenv("VMDNOOSPRAY")) { 00187 if (!havecpucaps || (havecpucaps && (cpucaps.flags & CPU_SSE4_1))) { 00188 #if defined(VMDLIBOSPRAY) 00189 int osprc = OSPRayDisplayDevice::OSPRay_Global_Init(); // call only ONCE 00190 if (osprc) { 00191 msgWarn << "Intel OSPRay renderer failed to initialize and is unavailable" << sendmsg; 00192 } else { 00193 add(new OSPRayDisplayDevice(vmdapp, 0)); 00194 #if !defined(__APPLE__) 00195 // XXX Since glwin hasn't yet been adapted to wrap FLTK, SDL, or 00196 // Apple-native Aqua/Cocoa, we can't enable the interactive RT window yet 00197 #if defined(VMDOPENGL) && defined(VMDOSPRAY_INTERACTIVE_OPENGL) 00198 if (!getenv("VMDNOOSPRAYINTERACTIVE")) { 00199 add(new OSPRayDisplayDevice(vmdapp, 1)); 00200 } 00201 #endif 00202 #endif 00203 } 00204 #endif 00205 00206 #if defined(VMDLIBOSPRAY2) 00207 OSPRay2DisplayDevice::OSPRay_Global_Init(); // call only ONCE 00208 int osprc = OSPRay2DisplayDevice::OSPRay_Global_Init(); // call only ONCE 00209 if (osprc) { 00210 msgWarn << "Intel OSPRay renderer failed to initialize and is unavailable" << sendmsg; 00211 } else { 00212 add(new OSPRay2DisplayDevice(vmdapp, 0)); 00213 #if !defined(__APPLE__) 00214 // XXX Since glwin hasn't yet been adapted to wrap FLTK, SDL, or 00215 // Apple-native Aqua/Cocoa, we can't enable the interactive RT window yet 00216 #if defined(VMDOPENGL) && defined(VMDOSPRAY_INTERACTIVE_OPENGL) 00217 add(new OSPRay2DisplayDevice(vmdapp, 1)); 00218 #endif 00219 #endif 00220 } 00221 #endif 00222 } else { 00223 msgWarn << "OSPRay renderer disabled, requires SSE 4.1 or greater" << sendmsg; 00224 } 00225 } 00226 #endif 00227 00228 add(new POV3DisplayDevice()); 00229 add(new VrmlDisplayDevice()); 00230 add(new Vrml2DisplayDevice()); 00231 add(new WavefrontDisplayDevice()); 00232 add(new X3DDisplayDevice()); 00233 add(new X3DOMDisplayDevice()); 00234 } 00235 00236 00237 // destructor, deallocate all the info 00238 FileRenderList::~FileRenderList(void) { 00239 for (int i=0;i<renderList.num();i++) 00240 delete renderList.data(i); 00241 00242 #if defined(VMDLIBOSPRAY) 00243 if (!getenv("VMDNOOSPRAY")) { 00244 OSPRayDisplayDevice::OSPRay_Global_Shutdown(); // call only ONCE 00245 } 00246 #endif 00247 00248 #if defined(VMDLIBOSPRAY2) 00249 if (!getenv("VMDNOOSPRAY")) { 00250 OSPRay2DisplayDevice::OSPRay_Global_Shutdown(); // call only ONCE 00251 } 00252 #endif 00253 00254 #if defined(VMDLIBANARI) 00255 if (!getenv("VMDNOANARI")) { 00256 ANARIDisplayDevice::ANARI_Global_Shutdown(); // call only ONCE 00257 } 00258 #endif 00259 00260 } 00261 00262 00263 // add a new render class with its corresponding name 00264 void FileRenderList::add(FileRenderer *newRenderer) { 00265 if (newRenderer) 00266 renderList.add_name(newRenderer->name, newRenderer); 00267 } 00268 00269 // figure out how many render classes are installed 00270 int FileRenderList::num(void) { 00271 return renderList.num(); 00272 } 00273 00274 // return the name for the ith class, returns NULL if out of range 00275 const char *FileRenderList::name(int i) { 00276 if (i>=0 && i < renderList.num()) { 00277 return renderList.name(i); 00278 } 00279 return NULL; 00280 } 00281 00282 // return the "pretty" name (used in GUIs) for the ith class. 00283 // returns NULL if out of range 00284 const char *FileRenderList::pretty_name(int i) { 00285 if (i>=0 && i < renderList.num()) { 00286 const FileRenderer * fr = renderList.data(i); 00287 return fr->pretty_name(); 00288 } 00289 return NULL; 00290 } 00291 00292 // find class (case-insensitive) for a renderer name, else return NULL 00293 FileRenderer *FileRenderList::find(const char *rname) { 00294 int indx = renderList.typecode(rname); 00295 00296 if (indx >= 0) 00297 return renderList.data(indx); 00298 else 00299 return NULL; 00300 } 00301 00302 // given a "pretty" render name, return the corresponding class 00303 FileRenderer *FileRenderList::find_pretty_name(const char *pretty) { 00304 int i; 00305 for (i=0; i<renderList.num(); i++) { 00306 if (!strcmp(pretty_name(i), pretty)) { 00307 return renderList.data(i); 00308 } 00309 } 00310 return NULL; 00311 } 00312 00313 // given a "pretty" renderer name, return the short name 00314 const char *FileRenderList::find_short_name_from_pretty_name(const char *pretty) { 00315 const FileRenderer *fr = find_pretty_name(pretty); 00316 if (fr) 00317 return fr->visible_name(); 00318 return NULL; 00319 } 00320 00321 int FileRenderList::render(const char *filename, const char *method, 00322 const char *extcmd) { 00323 msgInfo << "Rendering current scene to '" << filename << "' ..." << sendmsg; 00324 00325 FileRenderer *render = find(method); 00326 if (!render) { 00327 msgErr << "Invalid render method '" << method << sendmsg; 00328 return FALSE; 00329 } 00330 00331 // XXX Snapshot grabs the wrong buffer, so if we're doing snapshot, swap 00332 // the buffers, render, then swap back. 00333 if (!strcmp(method, "snapshot")) app->display->update(TRUE); 00334 int retval = app->scene->filedraw(render, filename, app->display); 00335 if (!strcmp(method, "snapshot")) app->display->update(TRUE); 00336 00337 // if successful, execute external command 00338 if (retval && extcmd && *extcmd != '0円') { 00339 JString strbuf(extcmd); 00340 strbuf.gsub("%s", filename); 00341 // substitute display %w and %h for display width and height 00342 int w=100, h=100; 00343 char buf[32]; 00344 app->display_get_size(&w, &h); 00345 sprintf(buf, "%d", w); 00346 strbuf.gsub("%w", buf); 00347 sprintf(buf, "%d", h); 00348 strbuf.gsub("%h", buf); 00349 msgInfo << "Executing post-render cmd '" << (const char *)strbuf << "' ..." << sendmsg; 00350 vmd_system(strbuf); 00351 } 00352 00353 // return result 00354 msgInfo << "Rendering complete." << sendmsg; 00355 return retval; 00356 } 00357 00358 int FileRenderList::set_render_option(const char *method, const char *option) { 00359 FileRenderer *ren; 00360 ren = find(method); 00361 if (!ren) { 00362 msgErr << "No rendering method '" << method << "' available." << sendmsg; 00363 return FALSE; 00364 } 00365 ren->set_exec_string(option); 00366 return TRUE; 00367 } 00368 00369 int FileRenderList::has_antialiasing(const char *method) { 00370 FileRenderer *ren = find(method); 00371 if (ren) return ren->has_antialiasing(); 00372 return 0; 00373 } 00374 00375 int FileRenderList::aasamples(const char *method, int aasamples) { 00376 FileRenderer *ren = find(method); 00377 if (ren) return ren->set_aasamples(aasamples); 00378 return -1; 00379 } 00380 00381 int FileRenderList::aosamples(const char *method, int aosamples) { 00382 FileRenderer *ren = find(method); 00383 if (ren) return ren->set_aosamples(aosamples); 00384 return -1; 00385 } 00386 00387 int FileRenderList::imagesize(const char *method, int *w, int *h) { 00388 FileRenderer *ren = find(method); 00389 if (!ren) return FALSE; 00390 return ren->set_imagesize(w, h); 00391 } 00392 00393 int FileRenderList::has_imagesize(const char *method) { 00394 FileRenderer *ren = find(method); 00395 if (!ren) return FALSE; 00396 return ren->has_imagesize(); 00397 } 00398 00399 int FileRenderList::aspectratio(const char *method, float *aspect) { 00400 FileRenderer *ren = find(method); 00401 if (!ren) return FALSE; 00402 *aspect = ren->set_aspectratio(*aspect); 00403 return TRUE; 00404 } 00405 00406 int FileRenderList::numformats(const char *method) { 00407 FileRenderer *ren = find(method); 00408 if (!ren) return 0; 00409 return ren->numformats(); 00410 } 00411 00412 const char *FileRenderList::format(const char *method, int i) { 00413 FileRenderer *ren = find(method); 00414 if (!ren) return NULL; 00415 if (i < 0) return ren->format(); 00416 return ren->format(i); 00417 } 00418 00419 int FileRenderList::set_format(const char *method, const char *format) { 00420 FileRenderer *ren = find(method); 00421 if (!ren) return FALSE; 00422 return ren->set_format(format); 00423 } 00424