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

OptiXRenderer.C

Go to the documentation of this file.
00001 /***************************************************************************
00002  *cr                                                                       
00003  *cr            (C) Copyright 1995-2019 The Board of Trustees of the           
00004  *cr                        University of Illinois                       
00005  *cr                         All Rights Reserved                        
00006  *cr                                                                   
00007  ***************************************************************************/
00008 
00009 /***************************************************************************
00010 * RCS INFORMATION:
00011 *
00012 *      $RCSfile: OptiXRenderer.C,v $
00013 *      $Author: johns $      $Locker:  $               $State: Exp $
00014 *      $Revision: 1.391 $         $Date: 2021/12/21 06:44:17 $
00015 *
00016 ***************************************************************************/
00075 // low-level OptiX headers have to be included first 
00076 // to prevent issues with compilation on Windows due to 
00077 // header-internal min/max macro (re)definition, etc.
00078 #include "OptiXRenderer.h"
00079 #include "OptiXShaders.h"
00080 
00081 #include <optix.h>
00082 #include <math.h>
00083 #include <stdlib.h>
00084 #include <stdio.h>
00085 #include <string.h>
00086 #if OPTIX_VERSION >= 50200
00087 #include <cuda_runtime.h>   // needed for cudaGetDeviceCount() etc
00088 #endif
00089 
00090 #if defined(__linux)
00091 #include <unistd.h>         // needed for symlink() in movie recorder
00092 #endif
00093 
00094 #include "VMDApp.h"         // needed for video streaming
00095 #include "VideoStream.h"    // needed for video streaming
00096 #include "DisplayDevice.h"  // needed for video streaming
00097 
00098 #include "Inform.h"
00099 #include "ImageIO.h"
00100 #include "Matrix4.h"
00101 #include "utilities.h"
00102 #include "WKFUtils.h"
00103 #include "ProfileHooks.h"
00104 #if defined(VMDOPTIXRTRT)
00105 #include "DispCmds.h"       // needed to process VMDDisplayList command tokens
00106 #endif
00107 
00108 // Enable the use of RT_GEOMETRY_BUILD_FLAG_RELEASE_BUFFERS on
00109 // RTX-specific triangle mesh vertex/index buffers optimization
00110 //
00111 // XXX This is presently disabled due to observed performance 
00112 //     losses compared to self-managed buffer deallocation when
00113 //     rendering frames in a tight loop.
00114 // #define VMDOPTIXRTXRELEASEBUFS 1
00115 
00116 // Enable HMD if VMD compiled with Oculus VR SDK or OpenHMD
00117 #if defined(VMDUSEOPENHMD) 
00118 #define VMDOPTIX_USE_HMD 1
00119 #endif
00120 
00121 #if defined(VMDOPTIX_USE_HMD)
00122 #include "HMDMgr.h"
00123 #endif
00124 
00125 // support Linux event I/O based joystick/spaceball input
00126 #if defined(VMDUSEEVENTIO)
00127 #include "eventio.h"
00128 #endif
00129 
00130 // enable the interactive ray tracing capability
00131 #if defined(VMDOPTIX_INTERACTIVE_OPENGL)
00132 #if (defined(WIN32) || defined(_WIN64)) && defined(_MSC_VER)
00133 #include <windows.h> // must include windows.h prior to GL
00134 #endif
00135 
00136 #include <GL/gl.h>
00137 #endif
00138 
00139 // the ORT_USE_TEMPLATE_SHADERS macro enables or disables the use of 
00140 // an array of template-specialized shaders for every combination of
00141 // scene-wide and material-specific shader features.
00142 #if defined(ORT_USE_TEMPLATE_SHADERS)
00143 static const char *onoffstr(int onoff) {
00144   return (onoff) ? "on" : "off";
00145 }
00146 #endif
00147 
00148 // OptiX 5.2 HW triangle APIs
00149 #define ORT_USE_HW_TRIANGLES 1
00150 
00151 // check environment for verbose timing/debugging output flags
00152 static OptiXRenderer::Verbosity get_verbose_flag(int inform=0) {
00153   OptiXRenderer::Verbosity verbose = OptiXRenderer::RT_VERB_MIN;
00154   char *verbstr = getenv("VMDOPTIXVERBOSE");
00155   if (verbstr != NULL) {
00156 //    printf("OptiXRenderer) verbosity config request: '%s'\n", verbstr);
00157     if (!strupcmp(verbstr, "MIN")) {
00158       verbose = OptiXRenderer::RT_VERB_MIN;
00159       if (inform)
00160         printf("OptiXRenderer) verbose setting: minimum\n");
00161     } else if (!strupcmp(verbstr, "TIMING")) {
00162       verbose = OptiXRenderer::RT_VERB_TIMING;
00163       if (inform)
00164         printf("OptiXRenderer) verbose setting: timing data\n");
00165     } else if (!strupcmp(verbstr, "DEBUG")) {
00166       verbose = OptiXRenderer::RT_VERB_DEBUG;
00167       if (inform)
00168         printf("OptiXRenderer) verbose setting: full debugging data\n");
00169     }
00170   }
00171   return verbose;
00172 }
00173 
00174 
00175 #if 0
00176 // Enable the use of OptiX timeout callbacks to help reduce the likelihood
00177 // of kernel timeouts when rendering on GPUs that are also used for display
00178 #define VMD_ENABLE_OPTIX_TIMEOUTS 1
00179 
00180 static int vmd_timeout_init = 0;
00181 static wkf_timerhandle cbtimer;
00182 static float vmd_timeout_lastcallback = 0.0f;
00183 
00184 static void vmd_timeout_reset(void) {
00185   if (vmd_timeout_init == 0) {
00186     vmd_timeout_init = 1;
00187     cbtimer = wkf_timer_create();
00188   }
00189   wkf_timer_start(cbtimer);
00190   vmd_timeout_lastcallback = wkf_timer_timenow(cbtimer);
00191 }
00192 
00193 static void vmd_timeout_time(float &deltat, float &totalt) {
00194   double now = wkf_timer_timenow(cbtimer);
00195   deltat = now - vmd_timeout_lastcallback;
00196   totalt = now;
00197   vmd_timeout_lastcallback = now;
00198 }
00199 
00200 static int vmd_timeout_cb(void) {
00201   int earlyexit = 0;
00202   float deltat, totalt;
00203 
00204   if (vmd_timeout_init == 0) 
00205     vmd_timeout_reset();
00206 
00207   vmd_timeout_time(deltat, totalt);
00208   printf("OptiXRenderer) timeout callback: since last %f sec, total %f sec\n",
00209          deltat, totalt); 
00210   return earlyexit; 
00211 }
00212 
00213 #endif
00214 
00215 
00216 // assumes current scope has Context variable named 'ctx'
00217 #define RTERR( func )                                                  \
00218   {                                                                    \
00219     RTresult code = func;                                              \
00220     if (code != RT_SUCCESS) {                                          \
00221       lasterror = code; /* preserve error code for subsequent tests */ \
00222       const char* message;                                             \
00223       rtContextGetErrorString(ctx, code, &message);                    \
00224       msgErr << "OptiXRenderer) ERROR: " << message << " ("            \
00225              << __FILE__ << ":" << __LINE__ << sendmsg;                \
00226     }                                                                  \
00227   }
00228 
00229 
00230 // assumes current scope has Context variable named 'ctx'
00231 // caller-provided 'code' error return value is used so that subsequent
00232 // code can use that for its own purposes.
00233 #define RTERR2( func, code )                                           \
00234   {                                                                    \
00235     code = func;                                                       \
00236     if (code != RT_SUCCESS) {                                          \
00237       lasterror = code; /* preserve error code for subsequent tests */ \
00238       const char* message;                                             \
00239       rtContextGetErrorString(ctx, code, &message);                    \
00240       msgErr << "OptiXRenderer) ERROR: " << message << " ("            \
00241              << __FILE__ << ":" << __LINE__ << sendmsg;                \
00242     }                                                                  \
00243   }
00244 
00245 
00246 #if defined(ORT_USERTXAPIS)
00247 
00248 //
00249 // helper routines for OptiX RTX hardware triangle APIs
00250 //
00251 
00252 // helper function that tests triangles for degeneracy and 
00253 // computes geometric normals
00254 __forceinline__ int hwtri_test_calc_Ngeom(const float3 * __restrict__ vertices, 
00255                                           float3 &Ngeometric) {
00256   // Compute unnormalized geometric normal
00257   float3 Ng = cross(vertices[1]-vertices[0], vertices[2]-vertices[0]);
00258 
00259   // Cull any degenerate triangles
00260   float area = length(Ng); // we want non-zero parallelogram area
00261   if (area > 0.0f && !isinf(area)) {
00262     // finish normalizing the geometric vector
00263     Ngeometric = Ng * (1.0f / area);
00264     return 0; // return success
00265   }
00266 
00267   return 1; // cull any triangle that fails area test
00268 }
00269 
00270 
00271 // helper function to allocate and map RT buffers for hardware triangles
00272 static void hwtri_alloc_bufs_v3f_n4u4_c4u(RTcontext ctx, int numfacets,
00273                                           RTbuffer &vbuf, float3 *&vertices,
00274                                           RTbuffer &nbuf, uint4 *&normals,
00275                                           RTbuffer &cbuf, int numcolors,
00276                                           uchar4 *&colors, 
00277                                           const float *uniform_color) {
00278   // Create and fill vertex/normal buffers
00279   rtBufferCreate(ctx, RT_BUFFER_INPUT, &vbuf);
00280   rtBufferSetFormat(vbuf, RT_FORMAT_FLOAT3);
00281   rtBufferSetSize1D(vbuf, numfacets * 3);
00282 
00283   rtBufferCreate(ctx, RT_BUFFER_INPUT, &nbuf);
00284   rtBufferSetFormat(nbuf, RT_FORMAT_UNSIGNED_INT4);
00285   rtBufferSetSize1D(nbuf, numfacets);
00286 
00287   rtBufferCreate(ctx, RT_BUFFER_INPUT, &cbuf);
00288   rtBufferSetFormat(cbuf, RT_FORMAT_UNSIGNED_BYTE4);
00289   rtBufferSetSize1D(cbuf, numcolors);
00290 
00291   rtBufferMap(vbuf, (void**) &vertices);
00292   rtBufferMap(nbuf, (void**) &normals);
00293   rtBufferMap(cbuf, (void**) &colors);
00294 
00295   if ((numcolors == 1) && (uniform_color != NULL)) {
00296     colors[0].x = uniform_color[0] * 255.0f;
00297     colors[0].y = uniform_color[1] * 255.0f;
00298     colors[0].z = uniform_color[2] * 255.0f;
00299     colors[0].w = 255;
00300   }
00301 }
00302  
00303 
00304 // helper function to set instance state variables to flag 
00305 // the availability of per-vertex normals and colors for the triangle mesh
00306 static void hwtri_set_vertex_flags(RTcontext ctx, 
00307                                    RTgeometryinstance instance_hwtri,
00308                                    RTbuffer nbuf, RTbuffer cbuf,
00309                                    int has_vertex_normals, 
00310                                    int has_vertex_colors) {
00311   RTresult lasterror = RT_SUCCESS;
00312 
00313   // register normal buffer
00314   RTvariable nbuf_v;
00315   RTERR( rtGeometryInstanceDeclareVariable(instance_hwtri, "normalBuffer", &nbuf_v) );
00316   RTERR( rtVariableSetObject(nbuf_v, nbuf) );
00317 
00318   // register color buffer
00319   RTvariable cbuf_v;
00320   RTERR( rtGeometryInstanceDeclareVariable(instance_hwtri, "colorBuffer", &cbuf_v) );
00321   RTERR( rtVariableSetObject(cbuf_v, cbuf) );
00322 
00323   // Enable/disable per-vertex normals (or use geometric normal)
00324   RTvariable has_vertex_normals_v;
00325   RTERR( rtGeometryInstanceDeclareVariable(instance_hwtri, "has_vertex_normals", &has_vertex_normals_v) );
00326   RTERR( rtVariableSet1i(has_vertex_normals_v, has_vertex_normals) );
00327 
00328   // Enable/disable per-vertex colors (or use uniform color) 
00329   RTvariable has_vertex_colors_v;
00330   RTERR( rtGeometryInstanceDeclareVariable(instance_hwtri, "has_vertex_colors", &has_vertex_colors_v) );
00331   RTERR( rtVariableSet1i(has_vertex_colors_v, has_vertex_colors) );
00332 
00333   if (lasterror != RT_SUCCESS) {
00334     printf("OptiXRenderer::hwtri_set_vertex_flags() error!\n");
00335   }
00336 }
00337 
00338 #endif
00339 
00340 
00341 #if defined(VMDOPTIX_INTERACTIVE_OPENGL)
00342 
00343 static void print_ctx_devices(RTcontext ctx) {
00344   unsigned int devcount = 0;
00345   rtContextGetDeviceCount(ctx, &devcount);
00346   if (devcount > 0) {
00347     int *devlist = (int *) calloc(1, devcount * sizeof(int));
00348     rtContextGetDevices(ctx, devlist);
00349     printf("OptiXRenderer) Using %d device%s:\n", 
00350            devcount, (devcount == 1) ? "" : "s");
00351 
00352     unsigned int d;
00353     for (d=0; d<devcount; d++) {
00354       char devname[20];
00355       int cudadev=-1, kto=-1;
00356       RTsize totalmem;
00357       memset(devname, 0, sizeof(devname));
00358 
00359       rtDeviceGetAttribute(devlist[d], RT_DEVICE_ATTRIBUTE_NAME, sizeof(devname), devname);
00360       rtDeviceGetAttribute(devlist[d], RT_DEVICE_ATTRIBUTE_EXECUTION_TIMEOUT_ENABLED, sizeof(int), &kto);
00361       rtDeviceGetAttribute(devlist[d], RT_DEVICE_ATTRIBUTE_CUDA_DEVICE_ORDINAL, sizeof(int), &cudadev);
00362       rtDeviceGetAttribute(devlist[d], RT_DEVICE_ATTRIBUTE_TOTAL_MEMORY, sizeof(totalmem), &totalmem);
00363 
00364       printf("OptiXRenderer) [%u] %-19s  CUDA[%d], %.1fGB RAM", 
00365              d, devname, cudadev, totalmem / (1024.0*1024.0*1024.0));
00366       if (kto) {
00367         printf(", KTO");
00368       }
00369       printf("\n");
00370     }
00371     printf("OptiXRenderer)\n");
00372 
00373     free(devlist); 
00374   }
00375 }
00376 
00377 #endif
00378 
00379 
00380 static int query_meminfo_ctx_devices(RTcontext &ctx, unsigned long &freemem, unsigned long &physmem) {
00381   freemem=0;
00382   physmem=0;
00383   RTresult lasterror = RT_SUCCESS;
00384 
00385   unsigned int devcount = 0;
00386   RTERR( rtContextGetDeviceCount(ctx, &devcount) );
00387   if (devcount > 0) {
00388     int *devlist = (int *) calloc(1, devcount * sizeof(int));
00389     RTERR( rtContextGetDevices(ctx, devlist) );
00390     unsigned int d;
00391     for (d=0; d<devcount; d++) {
00392       RTsize freememsz=0;
00393       RTsize physmemsz=0;
00394       int ordinal = devlist[d];
00395       RTERR( rtContextGetAttribute(ctx, static_cast<RTcontextattribute>(RT_CONTEXT_ATTRIBUTE_AVAILABLE_DEVICE_MEMORY+ordinal), sizeof(freememsz), &freememsz) );
00396       if (lasterror != RT_SUCCESS) {
00397         free(devlist);
00398         return -1;
00399       }
00400      
00401       RTERR( rtDeviceGetAttribute(devlist[d], RT_DEVICE_ATTRIBUTE_TOTAL_MEMORY, sizeof(physmemsz), &physmemsz) );
00402       if (lasterror != RT_SUCCESS) {
00403         free(devlist);
00404         return -1;
00405       }
00406 
00407       if (d==0) {
00408         freemem = freememsz;
00409         physmem = physmemsz;
00410       } else {
00411         if (freemem < freememsz)
00412           freemem = freememsz;
00413 
00414         if (physmem < physmemsz)
00415           physmem = physmemsz;
00416       }
00417     }
00418     free(devlist); 
00419     return 0;
00420   }
00421 
00422   return -1;
00423 }
00424 
00425 
00426 int OptiXPrintRayStats(RTbuffer raystats1_buffer, RTbuffer raystats2_buffer,
00427                        double rtruntime) {
00428   int rc = 0;
00429   RTcontext ctx;
00430   RTresult result;
00431   RTsize buffer_width, buffer_height;
00432   const char* error;
00433 
00434   rtBufferGetContext(raystats1_buffer, &ctx);
00435 
00436   // buffer must be 2-D (for now)
00437   unsigned int bufdim;
00438   if (rtBufferGetDimensionality(raystats1_buffer, &bufdim) != RT_SUCCESS) {
00439     msgErr << "OptiXPrintRayStats: Failed to get ray stats buffer dimensions!" << sendmsg;
00440     return -1;
00441   }
00442   if (bufdim != 2) {
00443     msgErr << "OptiXPrintRayStats: Output buffer is not 2-D!" << sendmsg;
00444     return -1;
00445   }
00446 
00447   result = rtBufferGetSize2D(raystats1_buffer, &buffer_width, &buffer_height);
00448   if (result != RT_SUCCESS) {
00449     // Get error from context
00450     rtContextGetErrorString(ctx, result, &error);
00451     msgErr << "OptiXRenderer) Error getting dimensions of buffers: " << error << sendmsg;
00452     return -1;
00453   }
00454 
00455   volatile uint4 *raystats1, *raystats2;
00456   result = rtBufferMap(raystats1_buffer, (void**) &raystats1);   
00457   result = rtBufferMap(raystats2_buffer, (void**) &raystats2);   
00458   if (result != RT_SUCCESS) {
00459     rtContextGetErrorString(ctx, result, &error);
00460     msgErr << "OptiXPrintRayStats: Error mapping stats buffers: "
00461            << error << sendmsg;
00462     return -1;
00463   }
00464 
00465   // no stats data
00466   if (buffer_width < 1 || buffer_height < 1 || 
00467       raystats1 == NULL || raystats2 == NULL) {
00468     msgErr << "OptiXPrintRayStats: No data in ray stats buffers!" << sendmsg;
00469     return -1;
00470   }
00471 
00472   // collect and sum all per-pixel ray stats
00473   int i;
00474   int totalsz = buffer_width * buffer_height;
00475   unsigned long misses, transkips;
00476   unsigned long primaryrays, shadowlights, shadowao, transrays, reflrays;
00477   misses = transkips = primaryrays = shadowlights 
00478          = shadowao = transrays = reflrays = 0;
00479 
00480   // accumulate per-pixel ray stats into totals
00481   for (i=0; i<totalsz; i++) {
00482     primaryrays  += raystats1[i].x;
00483     shadowlights += raystats1[i].y;
00484     shadowao     += raystats1[i].z;
00485     misses       += raystats1[i].w;
00486     transrays    += raystats2[i].x;
00487     transkips    += raystats2[i].y;
00488     // XXX raystats2[i].z unused at present...
00489     reflrays     += raystats2[i].w;
00490   }
00491   unsigned long totalrays = primaryrays + shadowlights + shadowao 
00492                           + transrays + reflrays;
00493 
00494   printf("OptiXRenderer)\n");
00495   printf("OptiXRenderer) VMD/OptiX Scene Ray Tracing Statistics:\n");
00496   printf("OptiXRenderer) ----------------------------------------\n");
00497   printf("OptiXRenderer) Image resolution: %lu x %lu \n", 
00498           buffer_width, buffer_height);
00499   printf("OptiXRenderer) ----------------------------------------\n");
00500   printf("OptiXRenderer)                     Misses: %lu\n", misses);
00501   printf("OptiXRenderer) Transmission Any-Hit Skips: %lu\n", transkips);
00502   printf("OptiXRenderer) ----------------------------------------\n");
00503   printf("OptiXRenderer)               Primary Rays: %lu\n", primaryrays);
00504   printf("OptiXRenderer)      Dir-Light Shadow Rays: %lu\n", shadowlights);
00505   printf("OptiXRenderer)             AO Shadow Rays: %lu\n", shadowao);
00506   printf("OptiXRenderer)          Transmission Rays: %lu\n", transrays);
00507   printf("OptiXRenderer)            Reflection Rays: %lu\n", reflrays);
00508   printf("OptiXRenderer) ----------------------------------------\n");
00509   printf("OptiXRenderer)                 Total Rays: %lu\n", totalrays); 
00510   printf("OptiXRenderer)                 Total Rays: %g\n", totalrays * 1.0); 
00511   if (rtruntime > 0.0) {
00512     printf("OptiXRenderer)                   Rays/sec: %g\n", totalrays / rtruntime); 
00513   }
00514   printf("OptiXRenderer)\n");
00515 
00516   result = rtBufferUnmap(raystats1_buffer);
00517   result = rtBufferUnmap(raystats2_buffer);
00518   if (result != RT_SUCCESS) {
00519     rtContextGetErrorString(ctx, result, &error);
00520     msgErr << "OptiXPrintRayStats: Error unmapping ray stats buffer: "
00521            << error << sendmsg;
00522     return -1;
00523   }
00524 
00525   return rc;
00526 }
00527 
00528 
00529 int OptiXWriteImage(const char* filename, int writealpha,
00530                     RTbuffer buffer, RTformat buffer_format,
00531                     RTsize buffer_width, RTsize buffer_height) {
00532   RTresult result;
00533 
00534   void * imageData;
00535   result = rtBufferMap(buffer, &imageData);
00536   if (result != RT_SUCCESS) {
00537     RTcontext ctx;
00538     const char* error;
00539     rtBufferGetContext(buffer, &ctx);
00540     rtContextGetErrorString(ctx, result, &error);
00541     msgErr << "OptiXWriteImage: Error mapping image buffer: " 
00542            << error << sendmsg;
00543     return -1;
00544   }
00545 
00546   // no image data
00547   if (buffer_width < 1 || buffer_height < 1 || imageData == NULL) {
00548     msgErr << "OptiXWriteImage: No image data in output buffer!" << sendmsg;
00549     return -1;
00550   }
00551 
00552   // write the image to a file, according to the buffer format
00553   int xs = buffer_width;
00554   int ys = buffer_height;
00555   int rc = 0;
00556   if (buffer_format == RT_FORMAT_FLOAT4) {
00557     if (writealpha) {
00558 //printf("Writing rgba4f alpha channel output image 2\n");
00559       if (write_image_file_rgba4f(filename, (const float *) imageData, xs, ys))
00560         rc = -1;
00561     } else {
00562       if (write_image_file_rgb4f(filename, (const float *) imageData, xs, ys))
00563         rc = -1;
00564     }
00565   } else if (buffer_format == RT_FORMAT_UNSIGNED_BYTE4) {
00566     if (writealpha) {
00567 //printf("Writing rgba4u alpha channel output image 2\n");
00568       if (write_image_file_rgba4u(filename, (const unsigned char *) imageData, xs, ys))
00569         rc = -1;
00570     } else {
00571       if (write_image_file_rgb4u(filename, (const unsigned char *) imageData, xs, ys))
00572         rc = -1;
00573     }
00574   } else {
00575     rc = -1;
00576   }
00577 
00578   result = rtBufferUnmap(buffer);
00579   if (result != RT_SUCCESS) {
00580     RTcontext ctx;
00581     const char* error;
00582     rtBufferGetContext(buffer, &ctx);
00583     rtContextGetErrorString(ctx, result, &error);
00584     msgErr << "OptiXWriteImage: Error unmapping image buffer: " 
00585            << error << sendmsg;
00586     return -1;
00587   }
00588 
00589   return rc;
00590 }
00591 
00592 
00593 int OptiXWriteImage(const char* filename, int writealpha, RTbuffer buffer) {
00594   RTresult result;
00595   RTformat buffer_format;
00596   RTsize buffer_width, buffer_height;
00597 
00598   // buffer must be 2-D
00599   unsigned int bufdim;
00600   if (rtBufferGetDimensionality(buffer, &bufdim) != RT_SUCCESS) {
00601     msgErr << "OptiXWriteImage: Failed to get output buffer dimensions!" << sendmsg;
00602     return -1;
00603   }
00604 
00605   if (bufdim != 2) {
00606     msgErr << "OptiXWriteImage: Output buffer is not 2-D!" << sendmsg;
00607     return -1;
00608   }
00609 
00610   void * imageData;
00611   result = rtBufferMap(buffer, &imageData);
00612   if (result != RT_SUCCESS) {
00613     RTcontext ctx;
00614     const char* error;
00615     rtBufferGetContext(buffer, &ctx);
00616     rtContextGetErrorString(ctx, result, &error);
00617     msgErr << "OptiXWriteImage: Error mapping image buffer: " 
00618            << error << sendmsg;
00619     return -1;
00620   }
00621 
00622   // no image data
00623   if (imageData == NULL) {
00624     msgErr << "OptiXWriteImage: No image data in output buffer!" << sendmsg;
00625     return -1;
00626   }
00627 
00628   result = rtBufferGetSize2D(buffer, &buffer_width, &buffer_height);
00629   if (result != RT_SUCCESS) {
00630     // Get error from context
00631     RTcontext ctx;
00632     const char* error;
00633     rtBufferGetContext(buffer, &ctx);
00634     rtContextGetErrorString(ctx, result, &error);
00635     msgErr << "OptiXRenderer) Error getting dimensions of buffer: " << error << sendmsg;
00636     return -1;
00637   }
00638 
00639   if (rtBufferGetFormat(buffer, &buffer_format) != RT_SUCCESS) {
00640     msgErr << "OptiXWriteImage: failed to query output buffer format!" 
00641            << sendmsg;
00642     return -1;
00643   }
00644 
00645   // write the image to a file, according to the buffer format
00646   int xs = buffer_width;
00647   int ys = buffer_height;
00648   int rc = 0;
00649 
00650   if (buffer_format == RT_FORMAT_FLOAT4) {
00651     if (writealpha) {
00652 //printf("Writing rgba4f alpha channel output image 1\n");
00653       if (write_image_file_rgba4f(filename, (const float *) imageData, xs, ys))
00654         rc = -1;
00655     } else {
00656       if (write_image_file_rgb4f(filename, (const float *) imageData, xs, ys))
00657         rc = -1;
00658     }
00659   } else if (buffer_format == RT_FORMAT_UNSIGNED_BYTE4) {
00660     if (writealpha) {
00661 //printf("Writing rgba4u alpha channel output image 1\n");
00662       if (write_image_file_rgba4u(filename, (const unsigned char *) imageData, xs, ys))
00663         rc = -1;
00664     } else {
00665       if (write_image_file_rgb4u(filename, (const unsigned char *) imageData, xs, ys))
00666         rc = -1;
00667     }
00668   } else {
00669     rc = -1;
00670   }
00671 
00672   result = rtBufferUnmap(buffer);
00673   if (result != RT_SUCCESS) {
00674     RTcontext ctx;
00675     const char* error;
00676     rtBufferGetContext(buffer, &ctx);
00677     rtContextGetErrorString(ctx, result, &error);
00678     msgErr << "OptiXWriteImage: Error unmapping image buffer: "
00679            << error << sendmsg;
00680     return -1;
00681   }
00682 
00683   return rc;
00684 }
00685 
00686 
00688 OptiXRenderer::OptiXRenderer(VMDApp *vmdapp) {
00689   PROFILE_PUSH_RANGE("OptiXRenderer::OptiXRenderer()", 0);
00690   app = vmdapp;                   // store VMDApp ptr for video streaming
00691   ort_timer = wkf_timer_create(); // create and initialize timer
00692   wkf_timer_start(ort_timer);
00693 
00694   // setup path to pre-compiled shader PTX code
00695   const char *vmddir = getenv("VMDDIR");
00696   if (vmddir == NULL)
00697     vmddir = ".";
00698   sprintf(shaderpath, "%s/shaders/%s", vmddir, "OptiXShaders.ptx");
00699 
00700   // allow runtime override of the default shader path for testing
00701   if (getenv("VMDOPTIXSHADERPATH")) {
00702     strcpy(shaderpath, getenv("VMDOPTIXSHADERPATH"));
00703     msgInfo << "User-override of OptiX shader path: " << getenv("VMDOPTIXSHADERPATH") << sendmsg;
00704   }
00705 
00706 #if defined(ORT_USERTXAPIS)
00707   rtx_enabled = 1;             // RTX execution mode enabled
00708   hwtri_enabled = 1;           // RTX hardware triangle APIs enabled by default
00709 #endif
00710 
00711   lasterror = RT_SUCCESS;      // begin with no error state set 
00712   context_created = 0;         // no context yet
00713   buffers_allocated = 0;       // flag no buffer allocated yet
00714   buffers_progressive = 0;     // buf bound using progressive API or not
00715   scene_created = 0;           // scene has been created
00716 
00717   // clear timers
00718   time_ctx_setup = 0.0;
00719   time_ctx_validate = 0.0;
00720   time_ctx_AS_build = 0.0;
00721   time_ray_tracing = 0.0;
00722   time_image_io = 0.0;
00723 
00724   // set default scene background state
00725   scene_background_mode = RT_BACKGROUND_TEXTURE_SOLID;
00726   memset(scene_bg_color,    0, sizeof(scene_bg_color));
00727   memset(scene_bg_grad_top, 0, sizeof(scene_bg_grad_top));
00728   memset(scene_bg_grad_bot, 0, sizeof(scene_bg_grad_bot));
00729   memset(scene_gradient,    0, sizeof(scene_gradient));
00730   scene_gradient_topval = 1.0f;
00731   scene_gradient_botval = 0.0f;
00732   // XXX this has to be recomputed prior to rendering..
00733   scene_gradient_invrange = 1.0f / (scene_gradient_topval - scene_gradient_botval);
00734 
00735   // zero out the array of material usage counts for the scene
00736   memset(material_special_counts, 0, sizeof(material_special_counts));
00737 
00738   cam_zoom = 1.0f;
00739   cam_stereo_eyesep = 0.06f;
00740   cam_stereo_convergence_dist = 2.0f;
00741 
00742   clipview_mode = RT_CLIP_NONE;      // VR HMD fade+clipping plane/sphere
00743   clipview_start = 1.0f;             // VR HMD fade+clipping radial start dist
00744   clipview_end = 0.2f;               // VR HMD fade+clipping radial end dist
00745 
00746   // check for VR headlight and HMD/camera view clipping plane/sphere
00747   if (getenv("VMDOPTIXCLIPVIEW")) {
00748     clipview_mode = RT_CLIP_SPHERE;
00749     msgInfo << "OptiXRenderer) Overriding default clipping mode with RT_CLIP_SPHERE" << sendmsg;
00750   }
00751   if (getenv("VMDOPTIXCLIPVIEWSTART")) {
00752     clipview_start = float(atof(getenv("VMDOPTIXCLIPVIEWSTART")));
00753     msgInfo << "OptiXRenderer) Overriding default clipping start: " 
00754             << clipview_start << sendmsg;
00755   }
00756   if (getenv("VMDOPTIXCLIPVIEWEND")) {
00757     clipview_start = float(atof(getenv("VMDOPTIXCLIPVIEWEND")));
00758     msgInfo << "OptiXRenderer) Overriding default clipping end: " 
00759             << clipview_start << sendmsg;
00760   }
00761 
00762   headlight_mode = RT_HEADLIGHT_OFF; // VR HMD headlight disabled by default
00763   if (getenv("VMDOPTIXHEADLIGHT")) {
00764     headlight_mode = RT_HEADLIGHT_ON;
00765     msgInfo << "OptiXRenderer) Overriding default headlight mode with RT_HEADLIGHT_ON" << sendmsg;
00766   }
00767 
00768   shadows_enabled = RT_SHADOWS_OFF;  // disable shadows by default 
00769   aa_samples = 0;                    // no AA samples by default
00770 
00771   ao_samples = 0;                    // no AO samples by default
00772   ao_direct = 0.3f;                  // AO direct contribution is 30%
00773   ao_ambient = 0.7f;                 // AO ambient contribution is 70%
00774   ao_maxdist = RT_DEFAULT_MAX;       // default is no max occlusion distance
00775 
00776   dof_enabled = 0;                   // disable DoF by default
00777   cam_dof_focal_dist = 2.0f;
00778   cam_dof_fnumber = 64.0f;
00779 
00780   fog_mode = RT_FOG_NONE;            // fog/cueing disabled by default
00781   fog_start = 0.0f;
00782   fog_end = 10.0f;
00783   fog_density = 0.32f;
00784 
00785   verbose = RT_VERB_MIN;  // keep console quiet except for perf/debugging cases
00786   check_verbose_env();    // see if the user has overridden verbose flag
00787 
00788   create_context();
00789   destroy_scene();        // zero out object counters, prepare for rendering
00790 
00791   PROFILE_POP_RANGE();
00792 }
00793         
00795 OptiXRenderer::~OptiXRenderer(void) {
00796   PROFILE_PUSH_RANGE("OptiXRenderer::~OptiXRenderer()", 0);
00797 
00798   if (context_created)
00799     destroy_context(); 
00800   wkf_timer_destroy(ort_timer);
00801 
00802   PROFILE_POP_RANGE();
00803 }
00804 
00805 
00806 void OptiXRenderer::check_verbose_env() {
00807   verbose = get_verbose_flag(1);
00808 }
00809 
00810 
00811 
00812 //
00813 // This routine enumerates the set of GPUs that are usable by OptiX,
00814 // both in terms of their compatibility with the OptiX library we have
00815 // compiled against, and also in terms of user preferences to exclude
00816 // particular GPUs, GPUs that have displays attached, and so on.
00817 //
00818 unsigned int OptiXRenderer::device_list(int **devlist, char ***devnames) {
00819   OptiXRenderer::Verbosity dl_verbose = get_verbose_flag();
00820   if (dl_verbose == RT_VERB_DEBUG)
00821      printf("OptiXRenderer) OptiXRenderer::device_list()\n");
00822 
00823   unsigned int count=0;
00824   RTresult devcntresult = rtDeviceGetDeviceCount(&count);
00825   if (devcntresult != RT_SUCCESS) {
00826 #if OPTIX_VERSION >= 50200
00827     if (devcntresult == RT_ERROR_OPTIX_NOT_LOADED) {
00828       int cudadevcount = 0;
00829       cudaGetDeviceCount(&cudadevcount);
00830       if (cudadevcount > 0) {
00831         printf("OptiXRenderer) ERROR: Failed to load OptiX shared library.\n");
00832         printf("OptiXRenderer)        NVIDIA driver may be too old.\n");
00833         printf("OptiXRenderer)        Check/update NVIDIA driver\n");
00834       }
00835     }
00836 #endif
00837 
00838     if (dl_verbose == RT_VERB_DEBUG) {
00839       printf("OptiXRenderer)   rtDeviceGetDeviceCount() returned error %08x\n",
00840              devcntresult);
00841       printf("OptiXRenderer)   No GPUs available\n"); 
00842     }
00843 
00844     count = 0;
00845     if (devlist != NULL)
00846       *devlist = NULL;
00847     if (devnames != NULL)
00848       *devnames = NULL;
00849 
00850     return 0;
00851   }
00852 
00853   if (dl_verbose == RT_VERB_DEBUG) {
00854     printf("OptiXRenderer) OptiX rtDeviceGetDeviceCount() reports\n");
00855     printf("OptiXRenderer) that %d GPUs are available\n", count);
00856   }
00857 
00858   // check to see if the user wants to limit what device(s) are used
00859   unsigned int gpumask = 0xffffffff;
00860   const char *gpumaskstr = getenv("VMDOPTIXDEVICEMASK");
00861   if (gpumaskstr != NULL) {
00862     unsigned int tmp;
00863     if (sscanf(gpumaskstr, "%x", &tmp) == 1) {
00864       gpumask = tmp;
00865       msgInfo << "Using OptiX device mask '"
00866               << gpumaskstr << "'" << sendmsg;
00867     } else {
00868       msgInfo << "Failed to parse OptiX GPU device mask string '"
00869               << gpumaskstr << "'" << sendmsg;
00870     }
00871   }
00872 
00873   if (devlist != NULL) {
00874     *devlist = NULL;
00875     if (count > 0) {
00876       *devlist = (int *) calloc(1, count * sizeof(int));  
00877     }
00878   }
00879   if (devnames != NULL) {
00880     *devnames = NULL;
00881     if (count > 0) {
00882       *devnames = (char **) calloc(1, count * sizeof(char *));  
00883     }
00884   }
00885 
00886   // walk through the list of available devices and screen out
00887   // any that may cause problems with the version of OptiX we are using
00888   unsigned int i, goodcount;
00889   for (goodcount=0,i=0; i<count; i++) {
00890     // check user-defined GPU device mask for OptiX...
00891     if (!(gpumask & (1 << i))) {
00892       if (dl_verbose == RT_VERB_DEBUG) {
00893         char msgbuf[1024];
00894         sprintf(msgbuf, "  Excluded GPU[%d] due to user-specified device mask\n", i);
00895         msgInfo << msgbuf << sendmsg;
00896       }
00897       continue;
00898     } 
00899 
00900     // check user-requested exclusion of devices with display timeouts enabled
00901     int timeoutenabled;
00902     rtDeviceGetAttribute(i, RT_DEVICE_ATTRIBUTE_EXECUTION_TIMEOUT_ENABLED, 
00903                          sizeof(int), &timeoutenabled);
00904     if (timeoutenabled && getenv("VMDOPTIXNODISPLAYGPUS")) {
00905       if (dl_verbose == RT_VERB_DEBUG) {
00906         char msgbuf[1024];
00907         sprintf(msgbuf, "  Excluded GPU[%d] due to user-specified display timeout exclusion \n", i);
00908         msgInfo << msgbuf << sendmsg;
00909       }
00910       continue;
00911     } 
00912 
00913     //
00914     // screen for viable compute capability for this version of OptiX
00915     //
00916     // XXX this should be unnecessary with OptiX 3.6.x and later (I hope)
00917     //
00918     int compute_capability[2];
00919     rtDeviceGetAttribute(i, RT_DEVICE_ATTRIBUTE_COMPUTE_CAPABILITY, 
00920                          sizeof(compute_capability), compute_capability);
00921 //    printf("OptiX GPU[%d] compute capability %d\n", i, compute_capability[0]);
00922 #if OPTIX_VERSION <= 3051
00923     // exclude Maxwell and later GPUs if we're running OptiX 3.5.1 or earlier
00924     if (compute_capability[0] > 3) {
00925       if (dl_verbose == RT_VERB_DEBUG) {
00926         char msgbuf[1024];
00927         sprintf(msgbuf, "  Excluded GPU[%d] due to unsupported compute capability\n", i);
00928         msgInfo << msgbuf << sendmsg;
00929       }
00930       continue;
00931     }
00932 #endif
00933 
00934     // record all usable GPUs we find...
00935     if (dl_verbose == RT_VERB_DEBUG) {
00936       char msgbuf[1024];
00937       sprintf(msgbuf, "Found usable GPU[%i]\n", i);
00938       msgInfo << msgbuf << sendmsg;
00939     }
00940 
00941     if (devlist != NULL) {
00942       if (dl_verbose == RT_VERB_DEBUG) {
00943         char msgbuf[1024];
00944         sprintf(msgbuf, "  Adding usable GPU[%i] to list[%d]\n", i, goodcount);
00945         msgInfo << msgbuf << sendmsg;
00946       }
00947       (*devlist)[goodcount] = i;
00948     }
00949 
00950     if (devnames != NULL) {
00951       char *namebuf = (char *) calloc(1, 65 * sizeof(char));
00952       rtDeviceGetAttribute(i, RT_DEVICE_ATTRIBUTE_NAME, 
00953                            64*sizeof(char), namebuf);
00954       if (dl_verbose == RT_VERB_DEBUG) {
00955         char msgbuf[1024];
00956         sprintf(msgbuf, "  Adding usable GPU[%i] to list[%d]: '%s'\n", i, goodcount, namebuf);
00957         msgInfo << msgbuf << sendmsg;
00958       }
00959       (*devnames)[goodcount] = namebuf;
00960     }
00961     goodcount++;
00962   }
00963 
00964   return goodcount;
00965 }
00966 
00967 
00968 unsigned int OptiXRenderer::device_count(void) {
00969   OptiXRenderer::Verbosity dl_verbose = get_verbose_flag();
00970   if (dl_verbose == RT_VERB_DEBUG)
00971      printf("OptiXRenderer) OptiXRenderer::device_count()\n");
00972 
00973 #if 1
00974   return device_list(NULL, NULL);
00975 #else
00976   unsigned int count=0;
00977   if (rtDeviceGetDeviceCount(&count) != RT_SUCCESS)
00978     count = 0;
00979   return count;
00980 #endif
00981 }
00982 
00983 
00984 unsigned int OptiXRenderer::optix_version(void) {
00985   OptiXRenderer::Verbosity dl_verbose = get_verbose_flag();
00986   if (dl_verbose == RT_VERB_DEBUG)
00987      msgInfo << "OptiXRenderer) OptiXRenderer::optix_version()" << sendmsg;
00988 
00989   unsigned int version=0;
00990   if (rtGetVersion(&version) != RT_SUCCESS)
00991     version = 0;
00992   return version;
00993 }
00994 
00995 
00996 int OptiXRenderer::material_shader_table_size(void) {
00997   // used for initialization info printed to console
00998 #if defined(ORT_USE_TEMPLATE_SHADERS)
00999   return ORTMTABSZ;
01000 #else
01001   return 1;
01002 #endif
01003 }
01004 
01005 
01006 void OptiXRenderer::create_context() {
01007   time_ctx_create = 0;
01008   if (context_created)
01009     return;
01010 
01011   double starttime = wkf_timer_timenow(ort_timer);
01012 
01013   if (verbose == RT_VERB_DEBUG) printf("OptiXRenderer) creating context...\n");
01014 
01015 #if defined(ORT_USERTXAPIS)
01016   // Starting with OptiX 6.0.0, the OptiX runtime can select either an 
01017   // RTX execution strategy, or a classic non-RTX execution strategy
01018   // using a new global API flag that takes effect at context creation time.
01019   // RTX mode is only supported on Maxwell and later
01020   // GPUs, earlier Kepler hardware do not support RTX mode.
01021   int rtxonoff = 1;
01022   if (getenv("VMDOPTIXNORTX") != NULL) {
01023     rtxonoff = 0;
01024 
01025     // if the RTX mode isn't on, then we can't use the hardware triangle APIs.
01026     rtx_enabled = 0;
01027     hwtri_enabled = 0;
01028   }
01029 
01030   // The OptiX RTX execution strategy mode has to be set very early on,
01031   // otherwise the API call will return without error, but the OptiX
01032   // runtime will ignore the state change and continue with the existing
01033   // execution strategy (e.g. the default of '0' if set too late...)
01034   if (rtGlobalSetAttribute(RT_GLOBAL_ATTRIBUTE_ENABLE_RTX, sizeof(rtxonoff), &rtxonoff) != RT_SUCCESS) {
01035     printf("OptiXRenderer) Error setting RT_GLOBAL_ATTRIBUTE_ENABLE_RTX!!!\n");
01036   } else {
01037     if (verbose == RT_VERB_TIMING || verbose == RT_VERB_DEBUG)
01038       printf("OptiXRenderer) OptiX RTX execution mode is %s.\n",
01039              (rtxonoff) ? "on" : "off");
01040   }
01041 #endif
01042 
01043   // Create our objects and set state
01044   RTresult ctxrc;
01045   RTERR2( rtContextCreate(&ctx), ctxrc );
01046   if (ctxrc != RT_SUCCESS) {
01047     msgErr << "OptiXRenderer) Failed to create OptiX rendering context" << sendmsg;
01048     context_created=0;
01049     return;
01050   }
01051 
01052   // screen and set what GPU device(s) are used for this context
01053   // We shouldn't need the compute capability exclusions post-OptiX 3.6.x,
01054   // but this will benefit from other updates.
01055   if (getenv("VMDOPTIXDEVICEMASK") != NULL) {
01056     int *optixdevlist;
01057     int optixdevcount = device_list(&optixdevlist, NULL);
01058     if (optixdevcount > 0) {
01059       RTERR( rtContextSetDevices(ctx, optixdevcount, optixdevlist) );
01060     }
01061     free(optixdevlist);
01062   } else if (getenv("VMDOPTIXDEVICE") != NULL) {
01063     int optixdev = atoi(getenv("VMDOPTIXDEVICE"));
01064     msgInfo << "Setting OptiX GPU device to: " << optixdev << sendmsg;
01065     RTERR( rtContextSetDevices(ctx, 1, &optixdev) );
01066   }
01067 
01068   // register ray types for both shadow and radiance rays
01069   RTERR( rtContextSetRayTypeCount(ctx, RT_RAY_TYPE_COUNT) );
01070 
01071   // flag to indicate whether we're running in progressive mode or not
01072   RTERR( rtContextDeclareVariable(ctx, "progressive_enabled", &progressive_enabled_v) );
01073   RTERR( rtVariableSet1i(progressive_enabled_v, 0) );
01074 
01075   // declare various internal state variables
01076   RTERR( rtContextDeclareVariable(ctx, "max_depth", &max_depth_v) );
01077   RTERR( rtContextDeclareVariable(ctx, "max_trans", &max_trans_v) );
01078   RTERR( rtContextDeclareVariable(ctx, "radiance_ray_type", &radiance_ray_type_v) );
01079   RTERR( rtContextDeclareVariable(ctx, "shadow_ray_type", &shadow_ray_type_v) );
01080   RTERR( rtContextDeclareVariable(ctx, "scene_epsilon", &scene_epsilon_v) );
01081 
01082   // create light buffers/variables now, populate at render time...
01083 #if defined(VMDOPTIX_LIGHTUSEROBJS)
01084   RTERR( rtContextDeclareVariable(ctx, "dir_light_list", &dir_light_list_v) );
01085   RTERR( rtContextDeclareVariable(ctx, "pos_light_list", &pos_light_list_v) );
01086 #else
01087   RTERR( rtContextDeclareVariable(ctx, "dir_lights", &dir_lightbuffer_v) );
01088   RTERR( rtBufferCreate(ctx, RT_BUFFER_INPUT, &dir_lightbuffer) );
01089   RTERR( rtBufferSetFormat(dir_lightbuffer, RT_FORMAT_USER) );
01090   RTERR( rtBufferSetElementSize(dir_lightbuffer, sizeof(DirectionalLight)) );
01091 
01092   RTERR( rtContextDeclareVariable(ctx, "pos_lights", &pos_lightbuffer_v) );
01093   RTERR( rtBufferCreate(ctx, RT_BUFFER_INPUT, &pos_lightbuffer) );
01094   RTERR( rtBufferSetFormat(pos_lightbuffer, RT_FORMAT_USER) );
01095   RTERR( rtBufferSetElementSize(pos_lightbuffer, sizeof(PositionalLight)) );
01096 #endif
01097 
01098   // Current accumulation subframe count, used as part of generating
01099   // AA and AO random number sequences
01100   RTERR( rtContextDeclareVariable(ctx, "accumCount", &accum_count_v) );
01101   RTERR( rtVariableSet1ui(accum_count_v, 0) );
01102 
01103   // AO direct lighting scale factors, max occlusion distance
01104   RTERR( rtContextDeclareVariable(ctx, "ao_direct", &ao_direct_v) );
01105   RTERR( rtContextDeclareVariable(ctx, "ao_ambient", &ao_ambient_v) );
01106   RTERR( rtContextDeclareVariable(ctx, "ao_maxdist", &ao_maxdist_v) );
01107 
01108   // shadows, antialiasing, ambient occlusion
01109   RTERR( rtContextDeclareVariable(ctx, "shadows_enabled", &shadows_enabled_v) );
01110   RTERR( rtContextDeclareVariable(ctx, "aa_samples", &aa_samples_v) );
01111   RTERR( rtContextDeclareVariable(ctx, "ao_samples", &ao_samples_v) );
01112 
01113   // background color / gradient
01114   RTERR( rtContextDeclareVariable(ctx, "scene_bg_color", &scene_bg_color_v) );
01115   RTERR( rtContextDeclareVariable(ctx, "scene_bg_color_grad_top", &scene_bg_grad_top_v) );
01116   RTERR( rtContextDeclareVariable(ctx, "scene_bg_color_grad_bot", &scene_bg_grad_bot_v) );
01117   RTERR( rtContextDeclareVariable(ctx, "scene_gradient", &scene_gradient_v) );
01118   RTERR( rtContextDeclareVariable(ctx, "scene_gradient_topval", &scene_gradient_topval_v) );
01119   RTERR( rtContextDeclareVariable(ctx, "scene_gradient_botval", &scene_gradient_botval_v) );
01120   RTERR( rtContextDeclareVariable(ctx, "scene_gradient_invrange", &scene_gradient_invrange_v) );
01121 
01122   // VR HMD variables
01123   RTERR( rtContextDeclareVariable(ctx, "clipview_mode", &clipview_mode_v) );
01124   RTERR( rtContextDeclareVariable(ctx, "clipview_start", &clipview_start_v) );
01125   RTERR( rtContextDeclareVariable(ctx, "clipview_end", &clipview_end_v) );
01126   RTERR( rtContextDeclareVariable(ctx, "headlight_mode", &headlight_mode_v) );
01127 
01128   // cueing/fog variables
01129   RTERR( rtContextDeclareVariable(ctx, "fog_mode", &fog_mode_v) );
01130   RTERR( rtContextDeclareVariable(ctx, "fog_start", &fog_start_v) );
01131   RTERR( rtContextDeclareVariable(ctx, "fog_end", &fog_end_v) );
01132   RTERR( rtContextDeclareVariable(ctx, "fog_density", &fog_density_v) );
01133 
01134   // variables for top level scene graph objects
01135   RTERR( rtContextDeclareVariable(ctx, "root_object", &root_object_v) );
01136   RTERR( rtContextDeclareVariable(ctx, "root_shadower", &root_shadower_v) );
01137 
01138   // define all of the standard camera params
01139   RTERR( rtContextDeclareVariable(ctx, "cam_zoom", &cam_zoom_v) );
01140   RTERR( rtContextDeclareVariable(ctx, "cam_pos", &cam_pos_v) );
01141   RTERR( rtContextDeclareVariable(ctx, "cam_U", &cam_U_v) );
01142   RTERR( rtContextDeclareVariable(ctx, "cam_V", &cam_V_v) );
01143   RTERR( rtContextDeclareVariable(ctx, "cam_W", &cam_W_v) );
01144 
01145   // define stereoscopic camera parameters
01146   RTERR( rtContextDeclareVariable(ctx, "cam_stereo_eyesep", &cam_stereo_eyesep_v) );
01147   RTERR( rtContextDeclareVariable(ctx, "cam_stereo_convergence_dist", &cam_stereo_convergence_dist_v) );
01148 
01149   // define camera DoF parameters
01150   RTERR( rtContextDeclareVariable(ctx, "cam_dof_focal_dist", &cam_dof_focal_dist_v) );
01151   RTERR( rtContextDeclareVariable(ctx, "cam_dof_aperture_rad", &cam_dof_aperture_rad_v) );
01152 
01153   RTERR( rtContextDeclareVariable(ctx, "accumulation_normalization_factor", &accum_norm_v) );
01154 
01155 
01156   //
01157   // allow runtime override of the default shader path for testing
01158   // this has to be done prior to all calls that load programs from
01159   // the shader PTX
01160   //
01161   if (getenv("VMDOPTIXSHADERPATH")) {
01162     strcpy(shaderpath, getenv("VMDOPTIXSHADERPATH"));
01163     if (verbose == RT_VERB_DEBUG) 
01164       printf("OptiXRenderer) user-override shaderpath: '%s'\n", shaderpath);
01165   }
01166 
01167   if (verbose >= RT_VERB_TIMING) {
01168     printf("OptiXRenderer) creating shader programs...\n");
01169     fflush(stdout);
01170   }
01171 
01172   // load and initialize all of the material programs
01173   init_materials();
01174 
01175   double time_materials = wkf_timer_timenow(ort_timer); 
01176   if (verbose >= RT_VERB_TIMING) {
01177     printf("OptiXRenderer)   ");
01178     printf("materials(%.1f) ", time_materials - starttime);
01179     fflush(stdout);
01180   }
01181 
01182 #if defined(ORT_RAYSTATS)
01183   // program for clearing the raystats buffers
01184   RTERR( rtProgramCreateFromPTXFile(ctx, shaderpath, "clear_raystats_buffers", &clear_raystats_buffers_pgm) );
01185 #endif
01186 
01187   // program for clearing the accumulation buffer
01188   RTERR( rtProgramCreateFromPTXFile(ctx, shaderpath, "clear_accumulation_buffer", &clear_accumulation_buffer_pgm) );
01189 
01190   // program for copying the accumulation buffer to the framebuffer
01191   RTERR( rtProgramCreateFromPTXFile(ctx, shaderpath, "draw_accumulation_buffer", &draw_accumulation_buffer_pgm) );
01192 
01193   // empty placeholder program for copying the accumulation buffer
01194   RTERR( rtProgramCreateFromPTXFile(ctx, shaderpath, "draw_accumulation_buffer_stub", &draw_accumulation_buffer_stub_pgm) );
01195 
01196   double time_fbops = wkf_timer_timenow(ort_timer);
01197   if (verbose >= RT_VERB_TIMING) {
01198     printf("fbops(%.1f) ", time_fbops - time_materials);
01199     fflush(stdout);
01200   }
01201 
01202   // register cubemap VR camera ray gen programs
01203   RTERR( rtProgramCreateFromPTXFile(ctx, shaderpath,
01204          "vmd_camera_cubemap", &ray_gen_pgm_cubemap) );
01205   RTERR( rtProgramCreateFromPTXFile(ctx, shaderpath,
01206          "vmd_camera_cubemap_dof", &ray_gen_pgm_cubemap_dof) );
01207   RTERR( rtProgramCreateFromPTXFile(ctx, shaderpath,
01208          "vmd_camera_cubemap_stereo", &ray_gen_pgm_cubemap_stereo) );
01209   RTERR( rtProgramCreateFromPTXFile(ctx, shaderpath,
01210          "vmd_camera_cubemap_stereo_dof", &ray_gen_pgm_cubemap_stereo_dof) );
01211 
01212   // register planetarium dome master camera ray gen programs
01213   RTERR( rtProgramCreateFromPTXFile(ctx, shaderpath,
01214          "vmd_camera_dome_master", &ray_gen_pgm_dome_master) );
01215   RTERR( rtProgramCreateFromPTXFile(ctx, shaderpath,
01216          "vmd_camera_dome_master_dof", &ray_gen_pgm_dome_master_dof) );
01217   RTERR( rtProgramCreateFromPTXFile(ctx, shaderpath,
01218          "vmd_camera_dome_master_stereo", &ray_gen_pgm_dome_master_stereo) );
01219   RTERR( rtProgramCreateFromPTXFile(ctx, shaderpath,
01220          "vmd_camera_dome_master_stereo_dof", &ray_gen_pgm_dome_master_stereo_dof) );
01221 
01222   // register 360-degree equirectantular projection of spherical camera
01223   RTERR( rtProgramCreateFromPTXFile(ctx, shaderpath,
01224          "vmd_camera_equirectangular", &ray_gen_pgm_equirectangular) );
01225   RTERR( rtProgramCreateFromPTXFile(ctx, shaderpath,
01226          "vmd_camera_equirectangular_dof", &ray_gen_pgm_equirectangular_dof) );
01227   RTERR( rtProgramCreateFromPTXFile(ctx, shaderpath,
01228          "vmd_camera_equirectangular_stereo", &ray_gen_pgm_equirectangular_stereo) );
01229   RTERR( rtProgramCreateFromPTXFile(ctx, shaderpath,
01230          "vmd_camera_equirectangular_stereo_dof", &ray_gen_pgm_equirectangular_stereo_dof) );
01231 
01232   // register Oculus Rift projection
01233   RTERR( rtProgramCreateFromPTXFile(ctx, shaderpath,
01234          "vmd_camera_oculus_rift", &ray_gen_pgm_oculus_rift) );
01235   RTERR( rtProgramCreateFromPTXFile(ctx, shaderpath,
01236          "vmd_camera_oculus_rift_dof", &ray_gen_pgm_oculus_rift_dof) );
01237   RTERR( rtProgramCreateFromPTXFile(ctx, shaderpath,
01238          "vmd_camera_oculus_rift_stereo", &ray_gen_pgm_oculus_rift_stereo) );
01239   RTERR( rtProgramCreateFromPTXFile(ctx, shaderpath,
01240          "vmd_camera_oculus_rift_stereo_dof", &ray_gen_pgm_oculus_rift_stereo_dof) );
01241 
01242   // register perspective camera ray gen programs
01243   RTERR( rtProgramCreateFromPTXFile(ctx, shaderpath,
01244          "vmd_camera_perspective", &ray_gen_pgm_perspective) );
01245   RTERR( rtProgramCreateFromPTXFile(ctx, shaderpath,
01246          "vmd_camera_perspective_dof", &ray_gen_pgm_perspective_dof) );
01247   RTERR( rtProgramCreateFromPTXFile(ctx, shaderpath,
01248          "vmd_camera_perspective_stereo", &ray_gen_pgm_perspective_stereo) );
01249   RTERR( rtProgramCreateFromPTXFile(ctx, shaderpath,
01250          "vmd_camera_perspective_stereo_dof", &ray_gen_pgm_perspective_stereo_dof) );
01251 
01252   // register othographic camera ray gen programs
01253   RTERR( rtProgramCreateFromPTXFile(ctx, shaderpath,
01254          "vmd_camera_orthographic", &ray_gen_pgm_orthographic) );
01255   RTERR( rtProgramCreateFromPTXFile(ctx, shaderpath,
01256          "vmd_camera_orthographic_dof", &ray_gen_pgm_orthographic_dof) );
01257   RTERR( rtProgramCreateFromPTXFile(ctx, shaderpath,
01258          "vmd_camera_orthographic_stereo", &ray_gen_pgm_orthographic_stereo) );
01259   RTERR( rtProgramCreateFromPTXFile(ctx, shaderpath,
01260          "vmd_camera_orthographic_stereo_dof", &ray_gen_pgm_orthographic_stereo_dof) );
01261 
01262   // miss programs for background (solid, gradient sphere/plane)
01263   RTERR( rtProgramCreateFromPTXFile(ctx, shaderpath, "miss_gradient_bg_sky_sphere", &miss_pgm_sky_sphere) );
01264   RTERR( rtProgramCreateFromPTXFile(ctx, shaderpath, "miss_gradient_bg_sky_plane", &miss_pgm_sky_ortho_plane) );
01265   RTERR( rtProgramCreateFromPTXFile(ctx, shaderpath, "miss_solid_bg", &miss_pgm_solid) );
01266 
01267   // exception handler program
01268   RTERR( rtProgramCreateFromPTXFile(ctx, shaderpath, "exception", &exception_pgm) );
01269 
01270   double time_cambgops = wkf_timer_timenow(ort_timer);
01271   if (verbose >= RT_VERB_TIMING) {
01272     printf("cambgops(%.1f) ", time_cambgops - time_fbops);
01273     fflush(stdout);
01274   }
01275 
01276   // cylinder array programs
01277   RTERR( rtProgramCreateFromPTXFile(ctx, shaderpath, "cylinder_array_bounds", &cylinder_array_bbox_pgm) );
01278   RTERR( rtProgramCreateFromPTXFile(ctx, shaderpath, "cylinder_array_intersect", &cylinder_array_isct_pgm) );
01279 
01280   // color-per-cylinder array programs
01281   RTERR( rtProgramCreateFromPTXFile(ctx, shaderpath, "cylinder_array_color_bounds", &cylinder_array_color_bbox_pgm) );
01282   RTERR( rtProgramCreateFromPTXFile(ctx, shaderpath, "cylinder_array_color_intersect", &cylinder_array_color_isct_pgm) );
01283 
01284   // color-per-ring array programs
01285   RTERR( rtProgramCreateFromPTXFile(ctx, shaderpath, "ring_array_color_bounds", &ring_array_color_bbox_pgm) );
01286   RTERR( rtProgramCreateFromPTXFile(ctx, shaderpath, "ring_array_color_intersect", &ring_array_color_isct_pgm) );
01287 
01288   // sphere array programs
01289   RTERR( rtProgramCreateFromPTXFile(ctx, shaderpath, "sphere_array_bounds", &sphere_array_bbox_pgm) );
01290   RTERR( rtProgramCreateFromPTXFile(ctx, shaderpath, "sphere_array_intersect", &sphere_array_isct_pgm) );
01291 
01292   // color-per-sphere array programs
01293   RTERR( rtProgramCreateFromPTXFile(ctx, shaderpath, "sphere_array_color_bounds", &sphere_array_color_bbox_pgm) );
01294   RTERR( rtProgramCreateFromPTXFile(ctx, shaderpath, "sphere_array_color_intersect", &sphere_array_color_isct_pgm) );
01295 
01296   // tricolor list programs
01297   RTERR( rtProgramCreateFromPTXFile(ctx, shaderpath, "tricolor_bounds", &tricolor_bbox_pgm) );
01298   RTERR( rtProgramCreateFromPTXFile(ctx, shaderpath, "tricolor_intersect", &tricolor_isct_pgm) );
01299 
01300   // c4u_n3b_v3f
01301   RTERR( rtProgramCreateFromPTXFile(ctx, shaderpath, "trimesh_c4u_n3b_v3f_bounds", &trimesh_c4u_n3b_v3f_bbox_pgm) );
01302   RTERR( rtProgramCreateFromPTXFile(ctx, shaderpath, "trimesh_c4u_n3b_v3f_intersect", &trimesh_c4u_n3b_v3f_isct_pgm) );
01303 
01304   // n3f_v3f
01305   RTERR( rtProgramCreateFromPTXFile(ctx, shaderpath, "trimesh_n3f_v3f_bounds", &trimesh_n3f_v3f_bbox_pgm) );
01306   RTERR( rtProgramCreateFromPTXFile(ctx, shaderpath, "trimesh_n3f_v3f_intersect", &trimesh_n3f_v3f_isct_pgm) );
01307 
01308   // n3b_v3f
01309   RTERR( rtProgramCreateFromPTXFile(ctx, shaderpath, "trimesh_n3b_v3f_bounds", &trimesh_n3b_v3f_bbox_pgm) );
01310   RTERR( rtProgramCreateFromPTXFile(ctx, shaderpath, "trimesh_n3b_v3f_intersect", &trimesh_n3b_v3f_isct_pgm) );
01311 
01312   // v3f
01313   RTERR( rtProgramCreateFromPTXFile(ctx, shaderpath, "trimesh_v3f_bounds", &trimesh_v3f_bbox_pgm) );
01314   RTERR( rtProgramCreateFromPTXFile(ctx, shaderpath, "trimesh_v3f_intersect", &trimesh_v3f_isct_pgm) );
01315 
01316   double time_geompgms = wkf_timer_timenow(ort_timer);
01317   if (verbose >= RT_VERB_TIMING) {
01318     printf("geompgms(%.1f) ", time_geompgms - time_cambgops);
01319     fflush(stdout);
01320   }
01321 
01322   if (verbose >= RT_VERB_TIMING) {
01323     printf("\n");
01324   }
01325 
01326   time_ctx_create = wkf_timer_timenow(ort_timer) - starttime;
01327   
01328   if (verbose == RT_VERB_TIMING || verbose == RT_VERB_DEBUG) {
01329     printf("OptiXRenderer) context creation time: %.2f\n", time_ctx_create);
01330   }
01331 
01332   context_created = 1;
01333 }
01334 
01335 
01336 void OptiXRenderer::setup_context(int w, int h) {
01337   double starttime = wkf_timer_timenow(ort_timer);
01338   time_ctx_setup = 0;
01339 
01340   lasterror = RT_SUCCESS; // clear any error state
01341   width = w;
01342   height = h;
01343 
01344   if (!context_created)
01345     return;
01346 
01347   check_verbose_env(); // update verbose flag if changed since last run
01348 
01349   // set default global ray tracing recursion depth and/or allow
01350   // runtime user override here.
01351   scene_max_depth = 20;
01352   if (getenv("VMDOPTIXMAXDEPTH")) {
01353     int maxdepth = atoi(getenv("VMDOPTIXMAXDEPTH"));
01354     if (maxdepth > 0 && maxdepth <= 30) {
01355       printf("OptiXRenderer) Setting maxdepth to %d...\n", maxdepth);
01356       scene_max_depth = maxdepth; // set context-wide property
01357       RTERR( rtVariableSet1ui(max_depth_v, scene_max_depth) );
01358     } else {
01359       printf("OptiXRenderer) ignoring out-of-range maxdepth to %d...\n", maxdepth);
01360     }
01361   } 
01362 
01363   scene_max_trans = scene_max_depth;
01364   if (getenv("VMDOPTIXMAXTRANS")) {
01365     int maxtrans = atoi(getenv("VMDOPTIXMAXTRANS"));
01366     if (maxtrans > 0 && maxtrans <= 30) {
01367       printf("OptiXRenderer) Setting maxtrans to %d...\n", maxtrans);
01368       scene_max_trans = maxtrans; // set context-wide property
01369       RTERR( rtVariableSet1ui(max_trans_v, scene_max_trans) );
01370     } else {
01371       printf("OptiXRenderer) ignoring out-of-range maxtrans to %d...\n", maxtrans);
01372     }
01373   }
01374 
01375   // set maxdepth and maxtrans with new values
01376   RTERR( rtVariableSet1ui(max_depth_v, scene_max_depth) );
01377   RTERR( rtVariableSet1ui(max_trans_v, scene_max_trans) );
01378 
01379   // assign indices to ray types
01380   RTERR( rtVariableSet1ui(radiance_ray_type_v, 0u) );
01381   RTERR( rtVariableSet1ui(shadow_ray_type_v, 1u) );
01382 
01383   // set default scene epsilon
01384   float scene_epsilon = 5.e-5f;
01385   RTERR( rtVariableSet1f(scene_epsilon_v, scene_epsilon) );
01386 
01387   // Current accumulation subframe count, used as part of generating
01388   // AA and AO random number sequences
01389   RTERR( rtVariableSet1ui(accum_count_v, 0) );
01390 
01391    // zero out the array of material usage counts for the scene
01392   memset(material_special_counts, 0, sizeof(material_special_counts));
01393   time_ctx_setup = wkf_timer_timenow(ort_timer) - starttime;
01394 }
01395 
01396 
01397 void OptiXRenderer::report_context_stats() {
01398   if (!context_created)
01399     return;
01400 
01401   unsigned int ctx_varcount=0;
01402   RTERR( rtContextGetVariableCount(ctx, &ctx_varcount) );
01403   printf("OptiXRenderer) ctx var cnt: %u\n", ctx_varcount);
01404 }
01405 
01406 
01407 void OptiXRenderer::destroy_scene() {
01408   double starttime = wkf_timer_timenow(ort_timer);
01409   time_ctx_destroy_scene = 0;
01410 
01411   // zero out all object counters
01412   cylinder_array_cnt = 0;
01413   cylinder_array_color_cnt = 0;
01414   ring_array_color_cnt = 0;
01415   sphere_array_cnt = 0;
01416   sphere_array_color_cnt = 0;
01417   tricolor_cnt = 0;
01418   trimesh_c4u_n3b_v3f_cnt = 0;
01419   trimesh_n3b_v3f_cnt = 0;
01420   trimesh_n3f_v3f_cnt = 0;
01421   trimesh_v3f_cnt = 0;
01422 
01423   if (!context_created)
01424     return;
01425 
01426   if (scene_created) {
01427     int i;
01428 
01429     RTERR( rtAccelerationDestroy(acceleration) );
01430 #if defined(ORT_USERTXAPIS)
01431     // OptiX RTX hardware-accelerated triangles API
01432     RTERR( rtAccelerationDestroy(trianglesacceleration) );
01433 #endif
01434 
01435     RTERR( rtAccelerationDestroy(root_acceleration) );
01436     RTERR( rtGroupDestroy(root_group) );
01437 
01438     RTERR( rtGeometryGroupDestroy(geometrygroup) );
01439 #if defined(ORT_USERTXAPIS)
01440     // OptiX RTX hardware-accelerated triangles API
01441     RTERR( rtGeometryGroupDestroy(geometrytrianglesgroup) );
01442 #endif
01443 
01444     int instcount = geominstancelist.num();
01445     for (i=0; i<instcount; i++) {
01446       RTERR( rtGeometryInstanceDestroy(geominstancelist[i]) );
01447     }
01448 
01449     int geomcount = geomlist.num();
01450     for (i=0; i<geomcount; i++) {
01451       RTERR( rtGeometryDestroy(geomlist[i]) );
01452     }
01453 
01454     geominstancelist.clear();
01455     geomlist.clear();
01456 
01457 #if defined(ORT_USERTXAPIS)
01458     // OptiX RTX hardware-accelerated triangles API
01459 #if (OPTIX_VERSION >= 60500)
01460     // XXX Destroying the RTX triangle instances can cause crashes,
01461     //     both in the OptiX 5.2 DEV build w/ triangle API 0.3,
01462     //     and also the production OptiX 6.0.0 build w/ driver 418.30.
01463     //     This may be caused by an interaction between our use of
01464     //     RT_GEOMETRY_BUILD_FLAG_RELEASE_BUFFERS in the triangle APIs
01465     //     and the instance nodes.
01466     //     As of OptiX 6.5.0 and driver version 440.44, this problem 
01467     //     seems to be corrected, and this workaround is no longer needed.
01468     int insttrianglescount = geomtrianglesinstancelist.num();
01469     for (i=0; i<insttrianglescount; i++) {
01470       RTERR( rtGeometryInstanceDestroy(geomtrianglesinstancelist[i]) );
01471     }
01472 #endif
01473 
01474     int geomtrianglescount = geomtriangleslist.num();
01475     for (i=0; i<geomtrianglescount; i++) {
01476       RTERR( rtGeometryTrianglesDestroy(geomtriangleslist[i]) );
01477     }
01478 
01479     geomtrianglesinstancelist.clear();
01480     geomtriangleslist.clear();
01481 #endif
01482 
01483     int bufcount = bufferlist.num();
01484     for (i=0; i<bufcount; i++) {
01485       RTERR( rtBufferDestroy(bufferlist[i]) );
01486     }
01487 
01488     bufferlist.clear();
01489   }
01490 
01491   materialcache.clear(); // ensure no materials live across renderings
01492 
01493   double endtime = wkf_timer_timenow(ort_timer);
01494   time_ctx_destroy_scene = endtime - starttime;
01495 
01496   scene_created = 0; // scene has been destroyed
01497 }
01498 
01499 
01500 int OptiXRenderer::set_accum_raygen_pgm(CameraProjection &proj, 
01501                                         int stereo_on, int dof_on) {
01502   //
01503   // XXX The ray tracing engine supports a number of camera models that
01504   //     are extremely difficult to implement effectively in OpenGL,
01505   //     particularly in the context of interactive rasterization.
01506   //     The control over use of these camera models is currently implemented
01507   //     solely through environment variables, which is undesirable, but
01508   //     necessary in the very short term until we come up with a way of
01509   //     exposing this in the VMD GUIs.  The environment variables currently
01510   //     override the incoming projection settings from VMD.
01511   //
01512 
01513 
01514   // VR cubemap
01515   if (getenv("VMDOPTIXCUBEMAP") != NULL) {
01516     msgInfo << "Overriding VMD camera projection mode with VR cubemap" << sendmsg;
01517     proj = RT_CUBEMAP;
01518   }
01519 
01520   // planetarium dome master
01521   if (getenv("VMDOPTIXDOMEMASTER") != NULL) {
01522     msgInfo << "Overriding VMD camera projection mode with planetarium dome master" << sendmsg;
01523     proj = RT_DOME_MASTER;
01524   }
01525 
01526   // 360-degree spherical projection into a rectangular (2w x 1h) image
01527   if (getenv("VMDOPTIXEQUIRECTANGULAR") != NULL) {
01528     msgInfo << "Overriding VMD camera projection mode with spherical equirectangular projection" << sendmsg;
01529     proj = RT_EQUIRECTANGULAR;
01530   }
01531 
01532   // Oculus Rift w/ barrel distortion applied
01533   if (getenv("VMDOPTIXOCULUSRIFT") != NULL) {
01534     msgInfo << "Overriding VMD camera projection mode with Oculus Rift projection" << sendmsg;
01535     proj = RT_OCULUS_RIFT;
01536   }
01537 
01538   // override stereo if an environment variable is set
01539   if (getenv("VMDOPTIXSTEREO") != NULL) {
01540     msgInfo << "Overriding VMD camera, enabling stereo" << sendmsg;
01541     stereo_on = 1;
01542   }
01543     
01544   // set the active ray gen program based on the active projection mode
01545   switch (proj) {
01546     default:
01547       msgErr << "OptiXRenderer) Illegal projection mode! Using perspective." << sendmsg;
01548       // XXX fall through to perspective is intentional...
01549 
01550     case RT_PERSPECTIVE:
01551       if (stereo_on) {
01552         if (dof_on) {
01553           RTERR( rtContextSetRayGenerationProgram(ctx, RT_RAY_GEN_ACCUMULATE, ray_gen_pgm_perspective_stereo_dof) );
01554         } else {
01555           RTERR( rtContextSetRayGenerationProgram(ctx, RT_RAY_GEN_ACCUMULATE, ray_gen_pgm_perspective_stereo) );
01556         }
01557       } else {
01558         if (dof_on) {
01559           RTERR( rtContextSetRayGenerationProgram(ctx, RT_RAY_GEN_ACCUMULATE, ray_gen_pgm_perspective_dof) );
01560         } else {
01561           RTERR( rtContextSetRayGenerationProgram(ctx, RT_RAY_GEN_ACCUMULATE, ray_gen_pgm_perspective) );
01562         }
01563       }
01564       break;
01565 
01566     case RT_ORTHOGRAPHIC:
01567       if (stereo_on) {
01568         if (dof_on) {
01569           RTERR( rtContextSetRayGenerationProgram(ctx, RT_RAY_GEN_ACCUMULATE, ray_gen_pgm_orthographic_stereo_dof) );
01570         } else {
01571           RTERR( rtContextSetRayGenerationProgram(ctx, RT_RAY_GEN_ACCUMULATE, ray_gen_pgm_orthographic_stereo) );
01572         }
01573       } else {
01574         if (dof_on) {
01575           RTERR( rtContextSetRayGenerationProgram(ctx, RT_RAY_GEN_ACCUMULATE, ray_gen_pgm_orthographic_dof) );
01576         } else {
01577           RTERR( rtContextSetRayGenerationProgram(ctx, RT_RAY_GEN_ACCUMULATE, ray_gen_pgm_orthographic) );
01578         }
01579       }
01580       break;
01581 
01582     case RT_CUBEMAP:
01583       if (stereo_on) {
01584         if (dof_on) {
01585           RTERR( rtContextSetRayGenerationProgram(ctx, RT_RAY_GEN_ACCUMULATE, ray_gen_pgm_cubemap_stereo_dof) );
01586         } else {
01587           RTERR( rtContextSetRayGenerationProgram(ctx, RT_RAY_GEN_ACCUMULATE, ray_gen_pgm_cubemap_stereo) );
01588         }
01589       } else {
01590         if (dof_on) {
01591           RTERR( rtContextSetRayGenerationProgram(ctx, RT_RAY_GEN_ACCUMULATE, ray_gen_pgm_cubemap_dof) );
01592         } else {
01593           RTERR( rtContextSetRayGenerationProgram(ctx, RT_RAY_GEN_ACCUMULATE, ray_gen_pgm_cubemap) );
01594         }
01595       }
01596       break;
01597 
01598     case RT_DOME_MASTER:
01599       if (stereo_on) {
01600         if (dof_on) {
01601           RTERR( rtContextSetRayGenerationProgram(ctx, RT_RAY_GEN_ACCUMULATE, ray_gen_pgm_dome_master_stereo_dof) );
01602         } else {
01603           RTERR( rtContextSetRayGenerationProgram(ctx, RT_RAY_GEN_ACCUMULATE, ray_gen_pgm_dome_master_stereo) );
01604         }
01605       } else {
01606         if (dof_on) {
01607           RTERR( rtContextSetRayGenerationProgram(ctx, RT_RAY_GEN_ACCUMULATE, ray_gen_pgm_dome_master_dof) );
01608         } else {
01609           RTERR( rtContextSetRayGenerationProgram(ctx, RT_RAY_GEN_ACCUMULATE, ray_gen_pgm_dome_master) );
01610         }
01611       }
01612       break;
01613 
01614     case RT_EQUIRECTANGULAR:
01615       if (stereo_on) {
01616         if (dof_on) {
01617           RTERR( rtContextSetRayGenerationProgram(ctx, RT_RAY_GEN_ACCUMULATE, ray_gen_pgm_equirectangular_stereo_dof) );
01618         } else {
01619           RTERR( rtContextSetRayGenerationProgram(ctx, RT_RAY_GEN_ACCUMULATE, ray_gen_pgm_equirectangular_stereo) );
01620         }
01621       } else {
01622         if (dof_on) {
01623           RTERR( rtContextSetRayGenerationProgram(ctx, RT_RAY_GEN_ACCUMULATE, ray_gen_pgm_equirectangular_dof) );
01624         } else {
01625           RTERR( rtContextSetRayGenerationProgram(ctx, RT_RAY_GEN_ACCUMULATE, ray_gen_pgm_equirectangular) );
01626         }
01627       }
01628       break;
01629 
01630     case RT_OCULUS_RIFT:
01631       if (stereo_on) {
01632         if (dof_on) {
01633           RTERR( rtContextSetRayGenerationProgram(ctx, RT_RAY_GEN_ACCUMULATE, ray_gen_pgm_oculus_rift_stereo_dof) );
01634         } else {
01635           RTERR( rtContextSetRayGenerationProgram(ctx, RT_RAY_GEN_ACCUMULATE, ray_gen_pgm_oculus_rift_stereo) );
01636         }
01637       } else {
01638         if (dof_on) {
01639           RTERR( rtContextSetRayGenerationProgram(ctx, RT_RAY_GEN_ACCUMULATE, ray_gen_pgm_oculus_rift_dof) );
01640         } else {
01641           RTERR( rtContextSetRayGenerationProgram(ctx, RT_RAY_GEN_ACCUMULATE, ray_gen_pgm_oculus_rift) );
01642         }
01643       }
01644       break;
01645   }
01646 
01647   return 0;
01648 }
01649 
01650 
01651 void OptiXRenderer::update_rendering_state(int interactive) {
01652   if (!context_created)
01653     return;
01654 
01655 #if defined(ORT_USERTXAPIS)
01656   // Permit VMD usage of the RTX hardware triangle API to 
01657   // be disabled at runtime, for debugging/comparison purposes.
01658   // This does not affect RTX execution mode, but rather VMD's 
01659   // internal usage of the RTX-specific triangle APIs.
01660   if (getenv("VMDOPTIXNOHWTRIANGLES") != NULL) {
01661     hwtri_enabled = 0;
01662   }
01663 #endif
01664 
01665   // update scene epsilon if necessary
01666   if (getenv("VMDOPTIXSCENEEPSILON") != NULL) {
01667     float scene_epsilon = float(atof(getenv("VMDOPTIXSCENEEPSILON")));
01668     printf("OptiXRenderer) user override of scene epsilon: %g\n", scene_epsilon);
01669     RTERR( rtVariableSet1f(scene_epsilon_v, scene_epsilon) );
01670   }
01671 
01672   int i;
01673   wkf_timer_start(ort_timer);
01674 
01675   // set interactive/progressive rendering flag
01676   RTERR( rtVariableSet1i(progressive_enabled_v, interactive) );
01677 
01678   long totaltris = tricolor_cnt + trimesh_c4u_n3b_v3f_cnt + 
01679                    trimesh_n3b_v3f_cnt + trimesh_n3f_v3f_cnt + trimesh_v3f_cnt;
01680 
01681   if (verbose == RT_VERB_TIMING || verbose == RT_VERB_DEBUG) {
01682     printf("OptiXRenderer) cyl %ld, ring %ld, sph %ld, tri %ld, tot: %ld  lt %ld\n",
01683            cylinder_array_cnt + cylinder_array_color_cnt,
01684            ring_array_color_cnt,
01685            sphere_array_cnt + sphere_array_color_cnt,
01686            totaltris,
01687            cylinder_array_cnt +  cylinder_array_color_cnt + ring_array_color_cnt + sphere_array_cnt + sphere_array_color_cnt + totaltris,
01688            directional_lights.num() + positional_lights.num());
01689   }
01690 
01691   if (verbose == RT_VERB_DEBUG) {
01692 #if defined(ORT_USE_TEMPLATE_SHADERS)
01693     if (getenv("VMDOPTIXFORCEGENERALSHADER") == NULL) {
01694       printf("OptiXRenderer) using template-specialized shaders and materials:\n");
01695       int i;
01696       for (i=0; i<ORTMTABSZ; i++) {
01697         if (material_special_counts[i] > 0) {
01698           printf("OptiXRenderer) material_special[%d] usage count: %d\n", 
01699                  i, material_special_counts[i]); 
01700     
01701           printf("OptiXRenderer)   "
01702                  "ClipView %s, "
01703                  "Headlight %s, "
01704                  "Fog %s, "
01705                  "Shadows %s, "
01706                  "AO %s, "
01707                  "Outline %s, "
01708                  "Refl %s, "
01709                  "Trans %s\n",
01710 #if defined(VMDOPTIX_VCA_TABSZHACK)
01711                  onoffstr(1),
01712                  onoffstr(1),
01713 #else
01714                  onoffstr(i & 128),
01715                  onoffstr(i &  64),
01716 #endif
01717                  onoffstr(i &  32),
01718                  onoffstr(i &  16),
01719                  onoffstr(i &   8),
01720                  onoffstr(i &   4),
01721                  onoffstr(i &   2),
01722                  onoffstr(i &   1));
01723         }
01724       }
01725       printf("OptiXRenderer)\n");
01726     } else {
01727       printf("OptiXRenderer) using fully general shader and materials.\n");
01728     }
01729 #else
01730     printf("OptiXRenderer) using fully general shader and materials.\n");
01731 #endif
01732   }
01733 
01734   RTERR( rtVariableSet3fv(scene_bg_color_v, scene_bg_color) );
01735   RTERR( rtVariableSet3fv(scene_bg_grad_top_v, scene_bg_grad_top) );
01736   RTERR( rtVariableSet3fv(scene_bg_grad_bot_v, scene_bg_grad_bot) );
01737   RTERR( rtVariableSet3fv(scene_gradient_v, scene_gradient) );
01738   RTERR( rtVariableSet1f(scene_gradient_topval_v, scene_gradient_topval) );
01739   RTERR( rtVariableSet1f(scene_gradient_botval_v, scene_gradient_botval) );
01740 
01741   if (verbose == RT_VERB_DEBUG) {
01742     printf("OptiXRenderer) HMD/camera view clipping mode: %d start: %.2f end: %.2f\n",
01743            clipview_mode, clipview_start, clipview_end);
01744 
01745     printf("OptiXRenderer) HMD/camera headlight mode: %d\n", headlight_mode);
01746 
01747     printf("OptiXRenderer) scene bg mode: %d\n", scene_background_mode);
01748 
01749     printf("OptiXRenderer) scene bgsolid: %.2f %.2f %.2f\n", 
01750            scene_bg_color[0], scene_bg_color[1], scene_bg_color[2]);
01751 
01752     printf("OptiXRenderer) scene bggradT: %.2f %.2f %.2f\n", 
01753            scene_bg_grad_top[0], scene_bg_grad_top[1], scene_bg_grad_top[2]);
01754 
01755     printf("OptiXRenderer) scene bggradB: %.2f %.2f %.2f\n", 
01756            scene_bg_grad_bot[0], scene_bg_grad_bot[1], scene_bg_grad_bot[2]);
01757   
01758     printf("OptiXRenderer) bg gradient: %f %f %f  top: %f  bot: %f\n",
01759            scene_gradient[0], scene_gradient[1], scene_gradient[2],
01760            scene_gradient_topval, scene_gradient_botval);
01761   }
01762 
01763   // update in case the caller changed top/bottom values since last recalc
01764   scene_gradient_invrange = 1.0f / (scene_gradient_topval - scene_gradient_botval);
01765   RTERR( rtVariableSet1f(scene_gradient_invrange_v, scene_gradient_invrange) );
01766 
01767   RTERR( rtVariableSet1i(clipview_mode_v, clipview_mode) );
01768   RTERR( rtVariableSet1f(clipview_start_v, clipview_start) );
01769   RTERR( rtVariableSet1f(clipview_end_v, clipview_end) );
01770   RTERR( rtVariableSet1i(headlight_mode_v, (int) headlight_mode) );
01771 
01772   RTERR( rtVariableSet1i(fog_mode_v, (int) fog_mode) );
01773   RTERR( rtVariableSet1f(fog_start_v, fog_start) );
01774   RTERR( rtVariableSet1f(fog_end_v, fog_end) );
01775   RTERR( rtVariableSet1f(fog_density_v, fog_density) );
01776 
01777   if (verbose == RT_VERB_DEBUG) {
01778     printf("OptiXRenderer) adding lights: dir: %ld  pos: %ld\n", 
01779            directional_lights.num(), positional_lights.num());
01780   }
01781 
01782 #if defined(VMDOPTIX_LIGHTUSEROBJS)
01783   DirectionalLightList dir_lights;
01784   memset(&dir_lights, 0, sizeof(DirectionalLightList));
01785   dir_lights.num_lights = directional_lights.num();
01786   int dlcount = directional_lights.num();
01787   dlcount = (dlcount > DISP_LIGHTS) ? DISP_LIGHTS : dlcount;
01788   for (i=0; i<dlcount; i++) {
01789     vec_copy((float*)(&dir_lights.dirs[i]), directional_lights[i].dir);
01790     vec_normalize((float*)&dir_lights.dirs[i]);
01791   }
01792   RTERR( rtVariableSetUserData(dir_light_list_v, sizeof(DirectionalLightList), &dir_lights) );
01793 
01794   PositionalLightList pos_lights;
01795   memset(&pos_lights, 0, sizeof(PositionalLightList));
01796   pos_lights.num_lights = positional_lights.num();
01797   int plcount = positional_lights.num();
01798   plcount = (plcount > DISP_LIGHTS) ? DISP_LIGHTS : plcount;
01799   for (i=0; i<plcount; i++) {
01800     vec_copy((float*)(&pos_lights.posns[i]), positional_lights[i].pos);
01801   }
01802   RTERR( rtVariableSetUserData(pos_light_list_v, sizeof(PositionalLightList), &pos_lights) );
01803 #else
01804   DirectionalLight *dlbuf;
01805   RTERR( rtBufferSetSize1D(dir_lightbuffer, directional_lights.num()) );
01806   RTERR( rtBufferMap(dir_lightbuffer, (void **) &dlbuf) );
01807   for (i=0; i<directional_lights.num(); i++) {
01808     vec_copy((float*)&dlbuf[i].dir, directional_lights[i].dir);
01809     vec_normalize((float*)&dlbuf[i].dir);
01810   }
01811   RTERR( rtBufferUnmap(dir_lightbuffer) );
01812   RTERR( rtVariableSetObject(dir_lightbuffer_v, dir_lightbuffer) );
01813 
01814   PositionalLight *plbuf;
01815   RTERR( rtBufferSetSize1D(pos_lightbuffer, positional_lights.num()) );
01816   RTERR( rtBufferMap(pos_lightbuffer, (void **) &plbuf) );
01817   for (i=0; i<positional_lights.num(); i++) {
01818     vec_copy((float*)&plbuf[i].pos, positional_lights[i].pos);
01819   }
01820   RTERR( rtBufferUnmap(pos_lightbuffer) );
01821   RTERR( rtVariableSetObject(pos_lightbuffer_v, pos_lightbuffer) );
01822 #endif
01823 
01824   if (verbose == RT_VERB_DEBUG) printf("OptiXRenderer) Finalizing OptiX scene graph...\n");
01825 
01826   // create group to hold instances
01827   int instcount = geominstancelist.num();
01828   if (verbose == RT_VERB_DEBUG) printf("OptiXRenderer) instance objects: %d\n", instcount);
01829 
01830   RTERR( rtGeometryGroupCreate(ctx, &geometrygroup) );
01831   RTERR( rtGeometryGroupSetChildCount(geometrygroup, instcount) );
01832   for (i=0; i<instcount; i++) {
01833     RTERR( rtGeometryGroupSetChild(geometrygroup, i, geominstancelist[i]) );
01834   }
01835 
01836 #if defined(ORT_USERTXAPIS)
01837   // OptiX RTX hardware-accelerated triangles API
01838   // create separate group for triangle instances
01839   int insttrianglescount = geomtrianglesinstancelist.num();
01840   if (verbose == RT_VERB_DEBUG) printf("OptiXRenderer) triangle instance objects: %d\n", insttrianglescount);
01841 
01842   RTERR( rtGeometryGroupCreate(ctx, &geometrytrianglesgroup) );
01843   RTERR( rtGeometryGroupSetChildCount(geometrytrianglesgroup, insttrianglescount) );
01844   for (i=0; i<insttrianglescount; i++) {
01845     RTERR( rtGeometryGroupSetChild(geometrytrianglesgroup, i, geomtrianglesinstancelist[i]) );
01846   }
01847 #endif
01848 
01849 
01850   // XXX we should create an acceleration object the instance shared
01851   //     by multiple PBC images
01852 
01853   // acceleration object for the geometrygroup
01854   RTERR( rtAccelerationCreate(ctx, &acceleration) );
01855 
01856   // Allow runtime override of acceleration builder and traverser
01857   // for performance testing/tuning
01858   const char *ort_builder   = getenv("VMDOPTIXBUILDER");
01859   const char *ort_traverser = getenv("VMDOPTIXTRAVERSER");
01860   if (ort_builder && ort_traverser) {
01861     RTERR( rtAccelerationSetBuilder(acceleration, ort_builder) );
01862     RTERR( rtAccelerationSetTraverser(acceleration, ort_traverser) );
01863     if (verbose == RT_VERB_DEBUG) {
01864       printf("OptiXRenderer) user-override of AS: builder: '%s' traverser '%s'\n",
01865              ort_builder, ort_traverser);
01866     }
01867   } else if (ort_builder) {
01868     RTERR( rtAccelerationSetBuilder(acceleration, ort_builder) );
01869     RTERR( rtAccelerationSetTraverser(acceleration, "Bvh") );
01870     if (verbose == RT_VERB_DEBUG) {
01871       printf("OptiXRenderer) user-override of AS builder: '%s' (def traverser '%s')\n",
01872              ort_builder, "Bvh");
01873     }
01874   } else {
01875 #if (OPTIX_VERSION >= 3050) && (OPTIX_VERSION < 3060) || (OPTIX_VERSION == 3063) || (OPTIX_VERSION == 3080)
01876     // OptiX 3.5.0 was the first to include the new fast "Trbvh" AS builder
01877     // OptiX 3.6.3 fixed Trbvh bugs on huge models
01878     // OptiX 3.8.0 has cured all known Trbvh bugs for VMD so far
01879     RTERR( rtAccelerationSetBuilder(acceleration, "Trbvh") );
01880     RTERR( rtAccelerationSetTraverser(acceleration, "Bvh") );
01881 #else
01882     // For older revs of OptiX (or those with bugs in Trbvh), 
01883     // the "MedianBvh" AS builder gives the best compromise between 
01884     // builder speed and ray tracing speed.
01885     // OptiX 3.6.[012] and 3.7.0 had Trbvh bugs on huge models that 
01886     // could cause VMD to crash in some cases
01887 //    RTERR( rtAccelerationSetBuilder(acceleration, "Sbvh") );
01888 //    RTERR( rtAccelerationSetBuilder(acceleration, "Bvh") );
01889     RTERR( rtAccelerationSetBuilder(acceleration, "MedianBvh") );
01890     RTERR( rtAccelerationSetTraverser(acceleration, "Bvh") );
01891 #endif
01892   }
01893 
01894  
01895   // allow user-override of the builder type (e.g. "GPU", or "CPU") when
01896   // the AS builder provides more than one choice.
01897   if (getenv("VMDOPTIXBUILDTYPE") != NULL) {
01898     const char *buildtypestr = getenv("VMDOPTIXBUILDTYPE");
01899     const char *curbuilderstr = NULL;
01900     RTERR( rtAccelerationGetBuilder(acceleration, &curbuilderstr) );
01901     if (!strcmp(curbuilderstr, "Trbvh")) {
01902       msgInfo << "OptiXRenderer) user-override of Trbvh AS build type: " 
01903               << buildtypestr << sendmsg;
01904       RTERR( rtAccelerationSetProperty(acceleration, "build_type", buildtypestr) );
01905     } else {
01906       msgErr << "OptiXRenderer) Can't set build type for AS builders other than Trbvh" << sendmsg; 
01907     }
01908   } 
01909 
01910 
01911   RTERR( rtGeometryGroupSetAcceleration(geometrygroup, acceleration) );
01912   RTERR( rtAccelerationMarkDirty(acceleration) );
01913 
01914 #if defined(ORT_USERTXAPIS)
01915   // OptiX RTX hardware-accelerated triangles API
01916   // Acceleration structure for triangle geometry
01917   RTERR( rtAccelerationCreate(ctx, &trianglesacceleration) );
01918   RTERR( rtAccelerationSetBuilder(trianglesacceleration, "Trbvh") );
01919   RTERR( rtAccelerationSetTraverser(trianglesacceleration, "Bvh") );
01920   RTERR( rtGeometryGroupSetAcceleration(geometrytrianglesgroup, trianglesacceleration) );
01921   RTERR( rtAccelerationMarkDirty(trianglesacceleration) );
01922 #endif
01923 
01924 
01925   // create the root node of the scene graph
01926   RTERR( rtGroupCreate(ctx, &root_group) );
01927 #if defined(ORT_USERTXAPIS)
01928   RTERR( rtGroupSetChildCount(root_group, 2) );
01929   RTERR( rtGroupSetChild(root_group, 0, geometrygroup) );
01930   RTERR( rtGroupSetChild(root_group, 1, geometrytrianglesgroup) );
01931 #else
01932   RTERR( rtGroupSetChildCount(root_group, 1) );
01933   RTERR( rtGroupSetChild(root_group, 0, geometrygroup) );
01934 #endif
01935   RTERR( rtVariableSetObject(root_object_v, root_group) );
01936   RTERR( rtVariableSetObject(root_shadower_v, root_group) );
01937 
01938   // create an acceleration object for the entire scene graph
01939   RTERR( rtAccelerationCreate(ctx, &root_acceleration) );
01940   RTERR( rtAccelerationSetBuilder(root_acceleration,"NoAccel") );
01941   RTERR( rtAccelerationSetTraverser(root_acceleration,"NoAccel") );
01942   RTERR( rtGroupSetAcceleration(root_group, root_acceleration) );
01943   RTERR( rtAccelerationMarkDirty(root_acceleration) );
01944   scene_created=1;
01945 
01946 
01947   // do final state variable updates before rendering begins
01948   if (verbose == RT_VERB_DEBUG) {
01949     printf("OptiXRenderer) cam zoom factor %f\n", cam_zoom);
01950     printf("OptiXRenderer) cam stereo eye separation  %f\n", cam_stereo_eyesep);
01951     printf("OptiXRenderer) cam stereo convergence distance %f\n", 
01952            cam_stereo_convergence_dist);
01953     printf("OptiXRenderer) cam DoF focal distance %f\n", cam_dof_focal_dist);
01954     printf("OptiXRenderer) cam DoF f/stop %f\n", cam_dof_fnumber);
01955   }
01956 
01957   // define all of the standard camera params
01958   RTERR( rtVariableSet1f(cam_zoom_v,  cam_zoom) );
01959   RTERR( rtVariableSet3f( cam_pos_v,  0.0f,  0.0f,  2.0f) );
01960   RTERR( rtVariableSet3f(   cam_U_v,  1.0f,  0.0f,  0.0f) );
01961   RTERR( rtVariableSet3f(   cam_V_v,  0.0f,  1.0f,  0.0f) );
01962   RTERR( rtVariableSet3f(   cam_W_v,  0.0f,  0.0f, -1.0f) );
01963 
01964   // define stereoscopic camera parameters
01965   RTERR( rtVariableSet1f(cam_stereo_eyesep_v, cam_stereo_eyesep) );
01966   RTERR( rtVariableSet1f(cam_stereo_convergence_dist_v, cam_stereo_convergence_dist) );
01967 
01968   // define camera DoF parameters
01969   RTERR( rtVariableSet1f(cam_dof_focal_dist_v, cam_dof_focal_dist) );
01970   RTERR( rtVariableSet1f(cam_dof_aperture_rad_v, cam_dof_focal_dist / (2.0f * cam_zoom * cam_dof_fnumber)) );
01971 
01972   // for batch mode rendering, we prefer correctness to speed, so 
01973   // we currently ignore USE_REVERSE_SHADOW_RAYS_DEFAULT except when
01974   // running interactively.  When the reverse ray optimizatoin is 100%
01975   // bulletproof, we will use it for batch rendering also.
01976   RTERR( rtVariableSet1i(shadows_enabled_v, 
01977                          (shadows_enabled) ? RT_SHADOWS_ON : RT_SHADOWS_OFF) );
01978 
01979   RTERR( rtVariableSet1i(ao_samples_v, ao_samples) );
01980   RTERR( rtVariableSet1f(ao_ambient_v, ao_ambient) );
01981   RTERR( rtVariableSet1f(ao_direct_v, ao_direct) );
01982   RTERR( rtVariableSet1f(ao_maxdist_v, ao_maxdist) );
01983   if (getenv("VMDOPTIXAOMAXDIST")) {
01984     float tmp = float(atof(getenv("VMDOPTIXAOMAXDIST")));
01985     if (verbose == RT_VERB_DEBUG) {
01986       printf("OptiXRenderer) setting AO maxdist: %f\n", tmp);
01987     }
01988     RTERR( rtVariableSet1f(ao_maxdist_v, tmp) );
01989   }
01990 
01991   if (verbose == RT_VERB_DEBUG) {
01992     printf("OptiXRenderer) setting sample counts:  AA %d  AO %d\n", aa_samples, ao_samples);
01993     printf("OptiXRenderer) setting AO factors:  AOA %f  AOD %f\n", ao_ambient, ao_direct);
01994   }
01995 
01996   //
01997   // Handle AA samples either internally with loops internal to 
01998   // each ray launch point thread, or externally by iterating over
01999   // multiple launches, adding each sample to an accumulation buffer,
02000   // or a hybrid combination of the two.  The final framebuffer output
02001   // is written by launching a special accumulation buffer drawing 
02002   // program that range clamps and converts the pixel data while copying
02003   // the GPU-local accumulation buffer to the final output buffer...
02004   //
02005   ext_aa_loops = 1;
02006   int totrays = (aa_samples + 1) * ((ao_samples > 0) ? ao_samples : 1);
02007   int maxrayspass = 16;
02008   if (getenv("VMDOPTIXMAXRAYSPERPASS") != NULL) {
02009     maxrayspass = atoi(getenv("VMDOPTIXMAXRAYSPERPASS"));
02010     printf("OptiXRenderer) User-override of max rays per pass: %d\n", maxrayspass);
02011   }
02012   if ((getenv("VMDOPTIXFORCEMULTIPASS") != NULL) || (totrays > maxrayspass)) {
02013     // if we have too much work for a single-pass rendering, we need to 
02014     // break it up into multiple passes or we risk having kernel timeouts
02015     ext_aa_loops = 1 + aa_samples;
02016     RTERR( rtVariableSet1i(aa_samples_v, 1) );
02017   } else { 
02018     // if the scene is simple, e.g. no AO rays and AA sample count is small,
02019     // we can run it in a single pass and get better performance
02020     RTERR( rtVariableSet1i(aa_samples_v, aa_samples + 1) );
02021   }
02022   RTERR( rtVariableSet1f(accum_norm_v, 1.0f / float(1 + aa_samples)) );
02023 
02024   if (verbose == RT_VERB_DEBUG) {
02025     if (ext_aa_loops > 1)
02026       printf("OptiXRenderer) Running OptiX multi-pass: %d loops\n", ext_aa_loops);
02027     else
02028       printf("OptiXRenderer) Running OptiX single-pass: %d total samples\n", 1+aa_samples);
02029   }
02030 
02031   // set the ray generation program to the active camera code...
02032   RTERR( rtContextSetEntryPointCount(ctx, RT_RAY_GEN_COUNT) );
02033   RTERR( rtContextSetRayGenerationProgram(ctx, RT_RAY_GEN_CLEAR_ACCUMULATION_BUFFER, clear_accumulation_buffer_pgm) );
02034 #if defined(ORT_RAYSTATS)
02035   RTERR( rtContextSetRayGenerationProgram(ctx, RT_RAY_GEN_CLEAR_RAYSTATS, clear_raystats_buffers_pgm) );
02036 #endif
02037 
02038   // set the active color accumulation ray gen program based on the 
02039   // camera/projection mode, stereoscopic display mode, 
02040   // and depth-of-field state
02041   set_accum_raygen_pgm(camera_projection, 0, dof_enabled);
02042 
02043   //
02044   // set the ray gen program to use for the copy/finish operations
02045   //
02046 #if defined(VMDOPTIX_PROGRESSIVEAPI)
02047   if (interactive) {
02048     RTERR( rtContextSetRayGenerationProgram(ctx, RT_RAY_GEN_COPY_FINISH, draw_accumulation_buffer_stub_pgm) );
02049   } else
02050 #endif
02051   {
02052     RTERR( rtContextSetRayGenerationProgram(ctx, RT_RAY_GEN_COPY_FINISH, draw_accumulation_buffer_pgm) );
02053   }
02054 
02055   // Link up miss program depending on background rendering mode
02056   switch (scene_background_mode) {
02057     case RT_BACKGROUND_TEXTURE_SKY_SPHERE:
02058       RTERR( rtContextSetMissProgram(ctx, RT_RAY_TYPE_RADIANCE, miss_pgm_sky_sphere) );
02059       break;
02060 
02061     case RT_BACKGROUND_TEXTURE_SKY_ORTHO_PLANE:
02062       RTERR( rtContextSetMissProgram(ctx, RT_RAY_TYPE_RADIANCE, miss_pgm_sky_ortho_plane) );
02063       break;
02064 
02065     case RT_BACKGROUND_TEXTURE_SOLID:
02066     default:
02067       RTERR( rtContextSetMissProgram(ctx, RT_RAY_TYPE_RADIANCE, miss_pgm_solid) );
02068       break;
02069   }
02070 
02071   // enable exception handling for all defined entry points
02072   unsigned int epcnt=0;
02073   RTERR( rtContextGetEntryPointCount(ctx, &epcnt) );
02074   unsigned int epidx;
02075   for (epidx=0; epidx<epcnt; epidx++) { 
02076     RTERR( rtContextSetExceptionProgram(ctx, epidx, exception_pgm) );
02077   }
02078 
02079   // enable all exceptions for debugging if requested
02080   if (getenv("VMDOPTIXDEBUG")) {
02081     printf("OptiXRenderer) Enabling all OptiX exceptions\n");
02082     RTERR( rtContextSetExceptionEnabled(ctx, RT_EXCEPTION_ALL, 1) );
02083   }
02084 
02085 
02086   // Check/update OptiX context-wide stack size calculations
02087   // based on required recursion depth, shader complexity, etc.
02088   int stacksizeadjusted=0;
02089 
02090 #if (OPTIX_VERSION >= 60000)
02091   // When running in RTX mode, OptiX >= 6.x provides an API to set
02092   // the maximum trace depth which is used to automatically compute the
02093   // required stack size.
02094   if (rtx_enabled) {
02095     // We need to tell OptiX to allow a recursion depth that includes
02096     // not only the surface hit, but also shadow feelers and any other
02097     // secondary rays that aren't being tracked explicitly by the 
02098     // internal recursion depth counter implemented in the top level 
02099     // ray gen and shading code.
02100     int newmaxdepth = scene_max_depth + 1;
02101 
02102     // A last-ditch workaround for issues observed in the field where
02103     // the requested max trace depth somehow didn't provide sufficient
02104     // stack space in practice.  This can be used for force OptiX to 
02105     // use the maximum stack size allowed by the RTX runtime.
02106     if (getenv("VMDOPTIXMAXSTACKSIZE")) {
02107       printf("OptiXRenderer) Setting RTX runtime to max depth / stack size\n");
02108 
02109       // The maximum recursion depth supported by OptiX 6.0 is 31.
02110       newmaxdepth = 31;
02111     }
02112 
02113     // Enforce maximum supported trace depth limit.
02114     // The maximum recursion depth supported by OptiX 6.0 is 31.
02115     if (newmaxdepth > 31)
02116       newmaxdepth = 31;
02117 
02118     RTERR( rtContextSetMaxTraceDepth(ctx, newmaxdepth) );
02119     RTERR( rtContextSetMaxCallableProgramDepth(ctx, newmaxdepth) );
02120 
02121     stacksizeadjusted = 1;
02122   }
02123 #endif
02124 
02125   // When not running in RTX mode, we revert to the old OptiX [1-5.x]
02126   // stack size APIs to set the stack size required for VMD scenes
02127   // with a typical recursion depth.
02128   // XXX The rtContext[GS]etStackSize() APIs are not supported when
02129   //     using the RTX execution strategy.  Although they don't (yet)
02130   //     return errors in that case, we protect against calling them here
02131   //     except when running in a non-RTX mode.  Presumably these APIs will
02132   //     be deprecated in future OptiX releases.
02133   if (!stacksizeadjusted) {
02134     // increase default OptiX stack size to prevent runtime failures
02135     RTsize ssz;
02136     rtContextGetStackSize(ctx, &ssz);
02137     if (verbose == RT_VERB_DEBUG) printf("OptiXRenderer) original stack size: %ld\n", ssz);
02138 
02139     // a decent default stack size is 7KB
02140     long newstacksize = 7 * 1024;
02141 
02142     // allow runtime user override of the OptiX stack size in 
02143     // case we need to render a truly massive scene
02144     if (getenv("VMDOPTIXSTACKSIZE")) {
02145       newstacksize = atoi(getenv("VMDOPTIXSTACKSIZE"));
02146       if (verbose == RT_VERB_DEBUG) printf("OptiXRenderer) user stack size override: %ld\n", newstacksize);
02147     }
02148     rtContextSetStackSize(ctx, newstacksize);
02149     rtContextGetStackSize(ctx, &ssz);
02150     if (verbose == RT_VERB_DEBUG) printf("OptiXRenderer) new stack size: %ld\n", ssz);
02151   }
02152 
02153 #if !defined(VMDOPTIX_PROGRESSIVEAPI)
02154   // Set print buffer size when using the old non-progressive APIs 
02155   rtContextSetPrintEnabled(ctx, 1);
02156   rtContextSetPrintBufferSize(ctx, 1*1024*1024); 
02157 #endif
02158 
02159 #if defined(VMD_ENABLE_OPTIX_TIMEOUTS)
02160   // Add a custom OptiX timeout callback to see if we can overcome
02161   // some of the timeout issues we've had previously
02162   double timeoutlimit = 0.5;
02163   const char *tmstr = getenv("VMDOPTIXTIMEOUTLIMIT");
02164   if (tmstr) {
02165     timeoutlimit = float(atof(tmstr));
02166     printf("Setting OptiX timeout: %f sec\n", timeoutlimit);
02167   }
02168 
02169   if (verbose == RT_VERB_DEBUG)
02170     printf("Setting OptiX timeout: %f sec\n", timeoutlimit);
02171   
02172   RTERR( rtContextSetTimeoutCallback(ctx, vmd_timeout_cb, timeoutlimit) );
02173 #endif
02174 }
02175 
02176 
02177 void OptiXRenderer::framebuffer_config(int fbwidth, int fbheight,
02178                                        int interactive) {
02179   if (!context_created)
02180     return;
02181 
02182   width = fbwidth;
02183   height = fbheight;
02184 
02185 #ifdef VMDOPTIX_PROGRESSIVEAPI
02186   // If VMD is using the progressive APIs, we have to check that
02187   // the requested framebuffer config matches the existing one in 
02188   // terms of bindings for streaming output, otherwise we have to 
02189   // destroy and re-create the framebuffer and any needed streaming
02190   // bindings.
02191   if (buffers_progressive != (interactive != 0)) {
02192     if (verbose == RT_VERB_DEBUG) {
02193       printf("OptiXRenderer) switching between progressive/non-progressive mode\n");
02194       printf("OptiXRenderer) remaking framebuffer\n");
02195     }
02196     framebuffer_destroy();
02197   }
02198 #endif
02199 
02200   // allocate and resize buffers to match request
02201   if (buffers_allocated) {
02202     // if the buffers already exist and match the current 
02203     // progressive/non-progressive rendering mode, just resize them
02204     if (verbose == RT_VERB_DEBUG) {
02205       printf("OptiXRenderer) resizing framebuffer\n");
02206     }
02207     framebuffer_resize(width, height);
02208   } else {
02209     // (re)allocate framebuffer and associated accumulation buffers if they
02210     // don't already exist or if they weren't bound properly for
02211     // current progressive/non-progressive rendering needs.
02212     if (verbose == RT_VERB_DEBUG) {
02213       printf("OptiXRenderer) creating framebuffer and accum. buffer\n");
02214     }
02215 
02216     // create intermediate GPU-local accumulation buffer
02217     RTERR( rtContextDeclareVariable(ctx, "accumulation_buffer", &accumulation_buffer_v) );
02218 
02219 #ifdef VMDOPTIX_PROGRESSIVEAPI
02220     if (interactive) {
02221       RTERR( rtBufferCreate(ctx, RT_BUFFER_OUTPUT, &accumulation_buffer) );
02222       buffers_progressive = 1;
02223     } else 
02224 #endif
02225     {
02226       RTERR( rtBufferCreate(ctx, RT_BUFFER_INPUT_OUTPUT | RT_BUFFER_GPU_LOCAL, &accumulation_buffer) );
02227       buffers_progressive = 0;
02228     }
02229 
02230     RTERR( rtBufferSetFormat(accumulation_buffer, RT_FORMAT_FLOAT4) );
02231     RTERR( rtBufferSetSize2D(accumulation_buffer, width, height) );
02232     RTERR( rtVariableSetObject(accumulation_buffer_v, accumulation_buffer) );
02233 
02234 #if defined(ORT_RAYSTATS)
02235     // (re)create intermediate GPU-local ray stats buffers
02236     // the ray stat buffers get cleared when clearing the accumulation buffer
02237     RTERR( rtContextDeclareVariable(ctx, "raystats1_buffer", &raystats1_buffer_v) );
02238     RTERR( rtBufferCreate(ctx, RT_BUFFER_OUTPUT, &raystats1_buffer) );
02239     RTERR( rtBufferSetFormat(raystats1_buffer, RT_FORMAT_UNSIGNED_INT4) );
02240     RTERR( rtBufferSetSize2D(raystats1_buffer, width, height) );
02241     RTERR( rtVariableSetObject(raystats1_buffer_v, raystats1_buffer) );
02242 
02243     RTERR( rtContextDeclareVariable(ctx, "raystats2_buffer", &raystats2_buffer_v) );
02244     RTERR( rtBufferCreate(ctx, RT_BUFFER_OUTPUT, &raystats2_buffer) );
02245     RTERR( rtBufferSetFormat(raystats2_buffer, RT_FORMAT_UNSIGNED_INT4) );
02246     RTERR( rtBufferSetSize2D(raystats2_buffer, width, height) );
02247     RTERR( rtVariableSetObject(raystats2_buffer_v, raystats2_buffer) );
02248 #endif
02249 
02250     // create output framebuffer
02251 #ifdef VMDOPTIX_PROGRESSIVEAPI
02252     if (interactive) {
02253       RTERR( rtBufferCreate(ctx, RT_BUFFER_PROGRESSIVE_STREAM, &framebuffer) );
02254 
02255       // allow user-override of default 5 Mbit/s video encoding bit rate
02256       int stream_bitrate = 5000000;
02257       if (getenv("VMDOPTIXBITRATE"))
02258         stream_bitrate = atoi(getenv("VMDOPTIXBITRATE"));
02259       RTERR( rtBufferSetAttribute(framebuffer, RT_BUFFER_ATTRIBUTE_STREAM_BITRATE, sizeof(int), &stream_bitrate) );
02260 
02261       // allow user-override of default 30 FPS target frame rate
02262       int stream_fps = 30;
02263       if (getenv("VMDOPTIXFPS"))
02264         stream_fps = atoi(getenv("VMDOPTIXFPS"));
02265       RTERR( rtBufferSetAttribute(framebuffer, RT_BUFFER_ATTRIBUTE_STREAM_FPS, sizeof(int), &stream_fps) );
02266             
02267       // allow user-override of Gamma
02268       float stream_gamma = 1.0f;
02269       if (getenv("VMDOPTIXGAMMS"))
02270         stream_gamma = atoi(getenv("VMDOPTIXGAMMA"));
02271       RTERR( rtBufferSetAttribute(framebuffer, RT_BUFFER_ATTRIBUTE_STREAM_GAMMA, sizeof(float), &stream_gamma) );
02272     } else
02273 #endif
02274     {
02275       RTERR( rtBufferCreate(ctx, RT_BUFFER_OUTPUT, &framebuffer) );
02276     }
02277 
02278     RTERR( rtBufferSetFormat(framebuffer, RT_FORMAT_UNSIGNED_BYTE4) );
02279     RTERR( rtBufferSetSize2D(framebuffer, width, height) );
02280 
02281 #ifdef VMDOPTIX_PROGRESSIVEAPI
02282     if (interactive) {
02283       RTERR( rtBufferBindProgressiveStream( framebuffer, accumulation_buffer) );
02284     } else
02285 #endif 
02286     {
02287       RTERR( rtContextDeclareVariable(ctx, "framebuffer", &framebuffer_v) );
02288       RTERR( rtVariableSetObject(framebuffer_v, framebuffer) );
02289     }
02290 
02291     buffers_allocated = 1;
02292   }
02293 }
02294 
02295 
02296 void OptiXRenderer::framebuffer_resize(int fbwidth, int fbheight) {
02297   if (!context_created)
02298     return;
02299 
02300   width = fbwidth;
02301   height = fbheight;
02302 
02303   if (buffers_allocated) {
02304     if (verbose == RT_VERB_DEBUG) 
02305       printf("OptiXRenderer) framebuffer_resize(%d x %d)\n", width, height);
02306 
02307     RTERR( rtBufferSetSize2D(framebuffer, width, height) );
02308     RTERR( rtBufferSetSize2D(accumulation_buffer, width, height) );
02309 #if defined(ORT_RAYSTATS)
02310     RTERR( rtBufferSetSize2D(raystats1_buffer, width, height) );
02311     RTERR( rtBufferSetSize2D(raystats2_buffer, width, height) );
02312 #endif
02313   }
02314 }
02315 
02316 
02317 void OptiXRenderer::framebuffer_map_rgb4u(unsigned char **imgrgb4u) {
02318   rtBufferMap(framebuffer, (void **) imgrgb4u);
02319 }
02320 
02321 
02322 void OptiXRenderer::framebuffer_unmap() {
02323   rtBufferUnmap(framebuffer);
02324 }
02325 
02326 
02327 void OptiXRenderer::framebuffer_destroy() {
02328   if (!context_created)
02329     return;
02330 
02331   if (buffers_allocated) {
02332 #if defined(ORT_RAYSTATS)
02333     RTERR( rtContextRemoveVariable(ctx, raystats1_buffer_v) );
02334     RTERR( rtBufferDestroy(raystats1_buffer) );
02335     RTERR( rtContextRemoveVariable(ctx, raystats2_buffer_v) );
02336     RTERR( rtBufferDestroy(raystats2_buffer) );
02337 #endif
02338     RTERR( rtContextRemoveVariable(ctx, accumulation_buffer_v) );
02339     RTERR( rtBufferDestroy(accumulation_buffer) );
02340 #ifndef VMDOPTIX_PROGRESSIVEAPI
02341     RTERR( rtContextRemoveVariable(ctx, framebuffer_v) );
02342 #endif
02343     RTERR( rtBufferDestroy(framebuffer) );
02344   }
02345   buffers_allocated = 0;
02346   buffers_progressive = 0;
02347 }
02348 
02349 
02350 void OptiXRenderer::render_compile_and_validate(void) {
02351   if (!context_created)
02352     return;
02353 
02354   //
02355   // finalize context validation, compilation, and AS generation 
02356   //
02357   double startctxtime = wkf_timer_timenow(ort_timer);
02358 
02359 
02360   // 
02361   // XXX need to add heuristics to prevent out-of-memory AS build failures on 
02362   //     versions of OptiX that don't allow multiple AS build attempts
02363   //
02364   // The memory usage of Trbvh is roughly (from Keith's email):
02365   //   68Byte * num_tris * 1.3 + 0.1*total GPU memory + user prim buffers.
02366   //
02367   // VMD should use this as an estimate of peak Trbvh memory demand and
02368   // force a switch from the GPU builder to a CPU builder, or if it's 
02369   // still too much.  Trbvh built on CPU still uses 2x the memory that
02370   // the geometry does, so there will still be cases where the only
02371   // viable route is to switch away from Trbvh entirely, e.g. use MedianBvh.
02372 #define ORT_AS_BUILD_MEM_HEURISTIC 1
02373 #if defined(ORT_AS_BUILD_MEM_HEURISTIC)
02374   if (getenv("VMDOPTIXNOMEMHEURISTIC") == NULL) {
02375     const char *curbuilderstr = NULL;
02376     RTERR( rtAccelerationGetBuilder(acceleration, &curbuilderstr) );
02377     if (!strcmp(curbuilderstr, "Trbvh")) {
02378       long totaltris = tricolor_cnt + trimesh_c4u_n3b_v3f_cnt +
02379                        trimesh_n3b_v3f_cnt + trimesh_n3f_v3f_cnt + 
02380                        trimesh_v3f_cnt;
02381 
02382       long totalobjs = cylinder_array_cnt + cylinder_array_color_cnt +
02383                        ring_array_color_cnt +
02384                        sphere_array_cnt + sphere_array_color_cnt +
02385                        totaltris;
02386 
02387       long totaluserbufsz = 
02388           cylinder_array_cnt * sizeof(vmd_cylinder) +
02389           cylinder_array_color_cnt * sizeof(vmd_cylinder_color) + 
02390           ring_array_color_cnt * sizeof(vmd_ring_color) +
02391           sphere_array_cnt * sizeof(vmd_sphere) + 
02392           sphere_array_color_cnt * sizeof(vmd_sphere_color) + 
02393           tricolor_cnt * sizeof(vmd_tricolor) + 
02394           trimesh_c4u_n3b_v3f_cnt * sizeof(vmd_trimesh_c4u_n3b_v3f) +
02395           trimesh_n3b_v3f_cnt * sizeof(vmd_trimesh_n3b_v3f) + 
02396           trimesh_n3f_v3f_cnt * sizeof(vmd_trimesh_n3f_v3f) + 
02397           trimesh_v3f_cnt * sizeof(vmd_trimesh_v3f);
02398 
02399       // Query the current state of all GPUs in the OptiX context
02400       // to determine the smallest amount of free memory, and 
02401       // the smallest amount of physical memory among all GPUs.
02402       unsigned long mingpufreemem, mingpuphysmem;
02403       if (query_meminfo_ctx_devices(ctx, mingpufreemem, mingpuphysmem)) {
02404         // If the GPU hardware query fails for some reason, we blindly
02405         // assume we've got a mostly vacant K20-like GPU with 4GB free 
02406         mingpufreemem = 4L * 1024L * 1024L * 1024L;
02407         mingpuphysmem = 6L * 1024L * 1024L * 1024L;
02408       }
02409       unsigned long tenpctgpumem = mingpuphysmem / 10;
02410 
02411       // 1.3 * 68 bytes == ~88 bytes
02412       unsigned long trbvhmemsz = totalobjs * 90L + tenpctgpumem;
02413       unsigned long totaltrbvhmemsz = trbvhmemsz + totaluserbufsz;
02414       unsigned long totaltrbvhmemszmb = totaltrbvhmemsz / (1024L * 1024L);
02415 
02416       if (totaltrbvhmemsz > mingpufreemem) {
02417         // issue warning, and try to build the AS using a different builder
02418         msgWarn << "OptiXRenderer) Predicted Trbvh AS peak GPU memory requirement exceeds capacity" << sendmsg;
02419         msgWarn << "OptiXRenderer) Min free GPU mem: " << (mingpufreemem / (1024L * 1024L)) << "MB" << sendmsg;
02420         msgWarn << "OptiXRenderer) Predicted Trbvh AS peak mem during build: " << totaltrbvhmemszmb << "MB" << sendmsg;
02421 
02422 #if 1
02423         // XXX the Trbvh CPU builder can segfault in some cases, e.g. on
02424         //     a 171M triangle mesh on a machine w/ 256GB physical mem.
02425         //     for now, we will only use MedianBvh as the fallback path until
02426         //     this issue is resolved with greater certainty.
02427         msgWarn << "OptiXRenderer) Switching to MedianBvh AS builder..." << sendmsg;   
02428         RTERR( rtAccelerationSetBuilder(acceleration, "MedianBvh") );
02429         RTERR( rtAccelerationSetTraverser(acceleration, "Bvh") );
02430 #else
02431 
02432         if (trbvhmemsz + totaluserbufsz > maxgpufreemem) {
02433           msgWarn << "OptiXRenderer) Switching to MedianBvh AS builder..." << sendmsg;   
02434           RTERR( rtAccelerationSetBuilder(acceleration, "MedianBvh") );
02435           RTERR( rtAccelerationSetTraverser(acceleration, "Bvh") );
02436         } else { 
02437           msgWarn << "OptiXRenderer) Switching to Trbvh CPU-based AS builder..." << sendmsg;   
02438           RTERR( rtAccelerationSetBuilder(acceleration, "Trbvh") );
02439           RTERR( rtAccelerationSetProperty(acceleration, "build_type", "CPU") );
02440           RTERR( rtAccelerationSetTraverser(acceleration, "Bvh") );
02441         }
02442 #endif
02443 
02444       }
02445     }
02446   }
02447 #endif
02448 
02449   if (verbose == RT_VERB_DEBUG) printf("OptiXRenderer) Finalizing OptiX rendering kernels...\n");
02450   RTERR( rtContextValidate(ctx) );
02451   if (lasterror != RT_SUCCESS) {
02452     printf("OptiXRenderer) An error occured validating the context. Rendering is aborted.\n");
02453     return;
02454   }
02455 
02456   RTERR( rtContextCompile(ctx) );
02457   if (lasterror != RT_SUCCESS) {
02458     printf("OptiXRenderer) An error occured compiling the context. Rendering is aborted.\n");
02459     return;
02460   }
02461 
02462   double contextinittime = wkf_timer_timenow(ort_timer);
02463   time_ctx_validate = contextinittime - startctxtime;
02464 
02465   //
02466   // Force OptiX to build the acceleration structure _now_ by using 
02467   // an empty launch.  This is done in OptiX sample 6...
02468   //
02469 // #define ORT_RETRY_FAILED_AS_BUILD 1
02470 #if defined(ORT_RETRY_FAILED_AS_BUILD)
02471   RTresult rc;
02472   rc = rtContextLaunch2D(ctx, RT_RAY_GEN_ACCUMULATE, 0, 0);
02473   RTERR( rc );
02474 #else
02475   RTERR( rtContextLaunch2D(ctx, RT_RAY_GEN_ACCUMULATE, 0, 0) );
02476 #endif
02477 
02478 #if defined(ORT_RETRY_FAILED_AS_BUILD)
02479   // XXX this never works right, I just get another error saying:
02480   //    "Cannot set builder while asynchronous building is in progress"
02481   if (rc == RT_ERROR_MEMORY_ALLOCATION_FAILED) {
02482     const char *curbuilderstr = NULL;
02483     RTERR( rtAccelerationGetBuilder(acceleration, &curbuilderstr) );
02484     printf("Current OptiX builder str: '%s'\n", curbuilderstr);
02485     if (!strcmp(curbuilderstr, "Trbvh")) {
02486       // clear previous error so we don't abort immediately...
02487       lasterror = RT_SUCCESS;
02488 
02489       // issue warning, and try to rebuild the AS using a different builder
02490       printf("OptiXRenderer) Trbvh AS ran out of GPU memory, retrying with MedianBvh...\n");
02491       RTERR( rtAccelerationSetBuilder(acceleration, "MedianBvh") );
02492       RTERR( rtAccelerationSetTraverser(acceleration, "Bvh") );
02493 
02494       // try re-validating and re-compiling context after changing the
02495       // AS builder to something that can survive GPU memory shortages
02496       render_compile_and_validate(); 
02497     }
02498   }
02499 #endif
02500 
02501   time_ctx_AS_build = wkf_timer_timenow(ort_timer) - contextinittime;
02502   if (verbose == RT_VERB_DEBUG) {
02503     printf("OptiXRenderer) launching render: %d x %d\n", width, height);
02504   }
02505 }
02506 
02507 
02508 #if defined(VMDOPTIX_INTERACTIVE_OPENGL)
02509 
02510 static void *createoptixwindow(const char *wintitle, int width, int height) {
02511   printf("OptiXRenderer) Creating OptiX window: %d x %d...\n", width, height);
02512 
02513   void *win = glwin_create(wintitle, width, height);
02514   while (glwin_handle_events(win, GLWIN_EV_POLL_NONBLOCK) != 0);
02515 
02516   glDrawBuffer(GL_BACK);
02517   glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
02518   glClearColor(0.0, 0.0, 0.0, 1.0); /* black */
02519   glViewport(0, 0, width, height);
02520   glClear(GL_COLOR_BUFFER_BIT);
02521 
02522   glShadeModel(GL_FLAT);
02523   glMatrixMode(GL_PROJECTION);
02524   glLoadIdentity();
02525   glOrtho(0.0, width, height, 0.0, -1.0, 1.0);
02526   glMatrixMode(GL_MODELVIEW);
02527   glLoadIdentity();
02528 
02529   glDrawBuffer(GL_BACK);
02530   glClear(GL_COLOR_BUFFER_BIT);
02531 
02532   glwin_swap_buffers(win);
02533 
02534   return win;
02535 }
02536 
02537 
02538 static void interactive_viewer_usage(RTcontext ctx, void *win) {
02539   printf("OptiXRenderer) VMD TachyonL-OptiX Interactive Ray Tracer help:\n");
02540   printf("OptiXRenderer) ===============================================\n");
02541 
02542   print_ctx_devices(ctx);
02543 
02544   // check for Spaceball/SpaceNavigator/Magellan input devices
02545   int havespaceball = ((glwin_spaceball_available(win)) && (getenv("VMDDISABLESPACEBALLXDRV") == NULL));
02546   printf("OptiXRenderer) Spaceball/SpaceNavigator/Magellan: %s\n",
02547          (havespaceball) ? "Available" : "Not available");
02548 
02549   // check for stereo-capable display
02550   int havestereo, havestencil;
02551   glwin_get_wininfo(win, &havestereo, &havestencil);
02552   printf("OptiXRenderer) Stereoscopic display: %s\n",
02553          (havestereo) ? "Available" : "Not available");
02554 
02555   // check for vertical retrace sync
02556   int vsync=0, rc=0;
02557   if ((rc = glwin_query_vsync(win, &vsync)) == GLWIN_SUCCESS) {
02558     printf("OptiXRenderer) Vert retrace sync: %s\n", (vsync) ? "On" : "Off");
02559   } else {
02560     printf("OptiXRenderer) Vert retrace sync: indeterminate\n");
02561   }
02562 
02563   printf("OptiXRenderer)\n");
02564   printf("OptiXRenderer) General controls:\n");
02565   printf("OptiXRenderer)   space: save numbered snapshot image\n");
02566   printf("OptiXRenderer)       =: reset to initial view\n");
02567   printf("OptiXRenderer)       h: print this help info\n");
02568   printf("OptiXRenderer)       p: print current rendering parameters\n");
02569   printf("OptiXRenderer)   ESC,q: quit viewer\n");
02570   printf("OptiXRenderer)\n");
02571   printf("OptiXRenderer) Display controls\n");
02572   printf("OptiXRenderer)      F1: override shadows on/off (off=AO off too)\n");
02573   printf("OptiXRenderer)      F2: override AO on/off\n");
02574   printf("OptiXRenderer)      F3: override DoF on/off\n");
02575   printf("OptiXRenderer)      F4: override Depth cueing on/off\n");
02576 #if defined(VMDOPTIX_USE_HMD)
02577   printf("OptiXRenderer)      F5: override HMD/camera clipping plane/sphere\n");
02578   printf("OptiXRenderer)      F6: override HMD/camera headlight\n");
02579   printf("OPtiXRenderer)      F7: toggle HMD interleaved drawing\n");
02580   printf("OPtiXRenderer)      F8: toggle HMD tex caching/update mode\n");
02581   printf("OPtiXRenderer)      F9: switch HMD lens distortion mode\n");
02582 #endif
02583 #ifdef USE_REVERSE_SHADOW_RAYS
02584   printf("OptiXRenderer)     F10: enable/disable shadow ray optimizations\n");
02585 #endif
02586   printf("OptiXRenderer)     F12: toggle full-screen display on/off\n");
02587   printf("OptiXRenderer)   1-9,0: override samples per update auto-FPS off\n");
02588   printf("OptiXRenderer)      Up: increase DoF focal distance\n");
02589   printf("OptiXRenderer)    Down: decrease DoF focal distance\n");
02590   printf("OptiXRenderer)    Left: decrease DoF f/stop\n");
02591   printf("OptiXRenderer)   Right: increase DoF f/stop\n");
02592   printf("OptiXRenderer)       S: toggle stereoscopic display on/off (if avail)\n");
02593   printf("OptiXRenderer)       a: toggle AA/AO auto-FPS tuning on/off (on)\n");
02594   printf("OptiXRenderer)       g: toggle gradient sky xforms on/off (on)\n");
02595   printf("OptiXRenderer)       l: toggle light xforms on/off (on)\n");
02596   printf("OptiXRenderer)\n");
02597   printf("OptiXRenderer) Mouse controls:\n");
02598   printf("OptiXRenderer)       f: mouse depth-of-field mode\n");
02599   printf("OptiXRenderer)       r: mouse rotation mode\n");
02600   printf("OptiXRenderer)       s: mouse scaling mode\n");
02601   printf("OptiXRenderer)       t: mouse translation mode\n");
02602 
02603   int movie_recording_enabled = (getenv("VMDOPTIXLIVEMOVIECAPTURE") != NULL);
02604   if (movie_recording_enabled) {
02605     printf("OptiXRenderer)\n");
02606     printf("OptiXRenderer) Movie recording controls:\n");
02607     printf("OptiXRenderer)       R: start/stop movie recording\n");
02608     printf("OptiXRenderer)       F: toggle movie FPS (24, 30, 60)\n");
02609   }
02610 }
02611 
02612 
02613 
02614 void OptiXRenderer::render_to_glwin(const char *filename, int writealpha) {
02615   int i;
02616 
02617   if (!context_created)
02618     return;
02619 
02620   enum RtMouseMode { RTMM_ROT=0, RTMM_TRANS=1, RTMM_SCALE=2, RTMM_DOF=3 };
02621   enum RtMouseDown { RTMD_NONE=0, RTMD_LEFT=1, RTMD_MIDDLE=2, RTMD_RIGHT=3 };
02622   RtMouseMode mm = RTMM_ROT;
02623   RtMouseDown mousedown = RTMD_NONE;
02624 
02625   // initialize HMD free-run flag to off until HMD code enumerates the 
02626   // hardware and passes all the way through initialization
02627   int hmd_freerun = 0;
02628 #if defined(VMDOPTIX_USE_HMD)
02629   void *hmd_warp = NULL;
02630 #endif
02631   int hmd_warp_drawmode=1;
02632 
02633   // default HMD distortion correction coefficients assume an Oculus DK2 HMD
02634   int hmd_warp_coeff_update=0; // warp equation was changed
02635   int hmd_warp_coeff_edit=1;   // which power of r to edit
02636   int hmd_warp_coeff_set=0;    // sets: 0=DK2, 1=MSR, 2=User
02637   const float dk2_warp_coeff[5] = { 1.000f, 0.000f, 0.600f, 0.000f, 0.000f };
02638 //  const float msr_warp_coeff[5] = { 1.000f, 0.290f, 0.195f, 0.045f, 0.360f };
02639   const float msr_warp_coeff[5] = { 0.950f, 0.330f, 0.195f, 0.045f, 0.360f };
02640   float user_warp_coeff[5]      = { 1.000f, 0.000f, 0.600f, 0.000f, 0.000f };
02641   float hmd_warp_coeff[5]       = { 1.000f, 0.000f, 0.600f, 0.000f, 0.000f };
02642 
02643   // obtain user-defined warp coefficients from environment variable if set
02644   if (getenv("VMDOPTIXHMDUSERWARPCOEFFS")) {
02645     printf("OptiXRenderer) user-override of default user-defined HMD warp coefficients\n");
02646     memset(user_warp_coeff, 0, sizeof(user_warp_coeff));
02647     int cnt=sscanf(getenv("VMDOPTIXHMDUSERWARPCOEFFS"), "%f %f %f %f %f",
02648                    &user_warp_coeff[0], &user_warp_coeff[1],
02649                    &user_warp_coeff[2], &user_warp_coeff[3],
02650                    &user_warp_coeff[4]);
02651     if (cnt != 5) {
02652       printf("OptiXRenderer) Warning: only parsed %d coefficients!\n", cnt);
02653     } else {
02654       printf("OptiXRenderer) user-defined warp coefficients: %d\n", cnt);
02655       printf("OptiXRenderer)  %.3f %.3f %.3f %.3f %.3f\n", 
02656              user_warp_coeff[0], user_warp_coeff[1], 
02657              user_warp_coeff[2], user_warp_coeff[3], user_warp_coeff[4]);
02658     }
02659   }
02660 
02661   // don't interleave extra HMD update/draw passes between buffer updates
02662   // unless the user wants us to, as a means of improving usability of
02663   // slow machines
02664   int hmd_interleave_draws = 0;
02665   if (getenv("VMDOPTIXHMDINTERLEAVEDRAWS")) {
02666     hmd_interleave_draws = 1;
02667     printf("OptiXRenderer) HMD GL draw call interleaving enabled\n");
02668   }
02669 
02670   int hmd_tex_caching = 0;
02671   if (getenv("VMDOPTIXHMDTEXCACHING")) {
02672     hmd_tex_caching = 1;
02673     printf("OptiXRenderer) HMD texture caching enabled\n");
02674   }
02675 
02676   // flag to skip the HMD GL draw calls for timing purposes
02677   int hmd_no_draw = 0;
02678   if (getenv("VMDOPTIXHMDNODRAW")) {
02679     hmd_no_draw = 1;
02680     printf("OptiXRenderer) HMD GL draw calls disabled\n");
02681   }
02682   
02683   // allow user-override of VR HMD sphere geometric res
02684   float hmd_fov = 95;
02685   if (getenv("VMDOPTIXHMDFOV")) {
02686     hmd_fov = float(atof(getenv("VMDOPTIXHMDFOV")));
02687     printf("OptiXRenderer) User-override of HMD FoV: %.2f\n", hmd_fov);
02688   }
02689 
02690   // allow user-override of VR HMD sphere geometric res
02691   int hmd_spres = 72; // 50 seems like the useful lower-bound spres setting
02692   if (getenv("VMDOPTIXHMDSPRES")) {
02693     hmd_spres = atoi(getenv("VMDOPTIXHMDSPRES"));
02694     printf("OptiXRenderer) User-override of HMD sph res: %d\n", hmd_spres);
02695   }
02696  
02697   // flags to interactively enable/disable shadows, AO, DoF
02698 #if defined(USE_REVERSE_SHADOW_RAYS) && defined(USE_REVERSE_SHADOW_RAYS_DEFAULT)
02699   int gl_shadows_on=(shadows_enabled) ? RT_SHADOWS_ON_REVERSE : RT_SHADOWS_OFF;
02700 #else
02701   int gl_shadows_on=(shadows_enabled) ? RT_SHADOWS_ON : RT_SHADOWS_OFF;
02702 #endif
02703 
02704   int gl_fs_on=0; // fullscreen window state
02705   int fsowsx=0, fsowsy=0; // store last win size before fullscreen
02706   int owsx=0, owsy=0; // last win size
02707   int gl_ao_on=(ao_samples > 0);
02708   int gl_dof_on, gl_dof_on_old;
02709   gl_dof_on=gl_dof_on_old=dof_enabled; 
02710   int gl_fog_on=(fog_mode != RT_FOG_NONE);
02711   int gl_clip_on=(clipview_mode != RT_CLIP_NONE);
02712   int gl_headlight_on=(headlight_mode != RT_HEADLIGHT_OFF);
02713 
02714   // Enable live recording of a session to a stream of image files indexed
02715   // by their display presentation time, mapped to the nearest frame index
02716   // in a fixed-frame-rate image sequence (e.g. 24, 30, or 60 FPS), 
02717   // to allow subsequent encoding into a standard movie format.
02718   // XXX this feature is disabled by default at present, to prevent people
02719   //     from accidentally turning it on during a live demo or the like
02720   int movie_recording_enabled = (getenv("VMDOPTIXLIVEMOVIECAPTURE") != NULL);
02721   int movie_recording_on = 0;
02722   double movie_recording_start_time = 0.0;
02723   int movie_recording_fps = 30;
02724   int movie_framecount = 0;
02725   int movie_lastframeindex = 0;
02726   const char *movie_recording_filebase = "vmdlivemovie.%05d.tga";
02727   if (getenv("VMDOPTIXLIVEMOVIECAPTUREFILEBASE"))
02728     movie_recording_filebase = getenv("VMDOPTIXLIVEMOVIECAPTUREFILEBASE");
02729 
02730   // Enable/disable Spaceball/SpaceNavigator/Magellan input 
02731   int spaceballenabled=(getenv("VMDDISABLESPACEBALLXDRV") == NULL) ? 1 : 0;
02732   int spaceballmode=0;       // default mode is rotation/translation
02733   int spaceballflightmode=0; // 0=moves object, 1=camera fly
02734   if (getenv("VMDOPTIXSPACEBALLFLIGHT"))
02735     spaceballflightmode=1;
02736 
02737   // total AA/AO sample count
02738   int totalsamplecount=0;
02739 
02740   // counter for snapshots of live image...
02741   int snapshotcount=0;
02742 
02743   // flag to enable automatic AO sample count adjustment for FPS rate control
02744 #if defined(VMDOPTIX_PROGRESSIVEAPI)
02745 #if 1
02746   int autosamplecount=0; // leave disabled for now
02747 #else
02748   int autosamplecount=1; // works partially in current revs of progressive API
02749 #endif
02750 #else
02751   int autosamplecount=1;
02752 #endif
02753 
02754   // flag to enable transformation of lights and gradient sky sphere, 
02755   // so that they track camera orientation as they do in the VMD OpenGL display
02756   int xformlights=1, xformgradientsphere=1;
02757 
02758   //
02759   // allocate or reconfigure the framebuffer, accumulation buffer, 
02760   // and output streams required for progressive rendering, either
02761   // using the new progressive APIs, or using our own code.
02762   //
02763   // Unless overridden by environment variables, we use the incoming
02764   // window size parameters from VMD to initialize the RT image dimensions.
02765   // If image size is overridden, often when using HMDs, the incoming 
02766   // dims are window dims are used to size the GL window, but the image size
02767   // is set independently.
02768   int wsx=width, wsy=height;
02769   const char *imageszstr = getenv("VMDOPTIXIMAGESIZE");
02770   if (imageszstr) {
02771     if (sscanf(imageszstr, "%d %d", &width, &height) != 2) {
02772       width=wsx;
02773       height=wsy;
02774     } 
02775   } 
02776 
02777   framebuffer_config(width, height, 1);
02778 
02779   // prepare the majority of OptiX rendering state before we go into 
02780   // the interactive rendering loop
02781   update_rendering_state(1);
02782   render_compile_and_validate();
02783 
02784   // make a copy of state we're going to interactively manipulate,
02785   // so that we can recover to the original state on-demand
02786   int samples_per_pass = 1;
02787   int force_ao_1 = 0; // whether or not to force AO count per pass to 1
02788   int cur_aa_samples = aa_samples;
02789   int cur_ao_samples = ao_samples;
02790   float cam_zoom_orig = cam_zoom;
02791   float scene_gradient_orig[3] = {0.0f, 1.0f, 0.0f};
02792   vec_copy(scene_gradient_orig, scene_gradient);
02793 
02794   float cam_pos_orig[3] = {0.0f, 0.0f, 2.0f};
02795   float cam_U_orig[3] = {1.0f, 0.0f, 0.0f};
02796   float cam_V_orig[3] = {0.0f, 1.0f, 0.0f};
02797   float cam_W_orig[3] = {0.0f, 0.0f, -1.0f};
02798   float cam_pos[3], cam_U[3], cam_V[3], cam_W[3];
02799   float hmd_U[3], hmd_V[3], hmd_W[3];
02800 
02801   vec_copy(cam_pos, cam_pos_orig);
02802   vec_copy(cam_U, cam_U_orig);
02803   vec_copy(cam_V, cam_V_orig);
02804   vec_copy(cam_W, cam_W_orig);
02805 
02806   // copy light directions
02807   DirectionalLight *cur_dlights = (DirectionalLight *) calloc(1, directional_lights.num() * sizeof(DirectionalLight));
02808   for (i=0; i<directional_lights.num(); i++) {
02809     vec_copy((float*)&cur_dlights[i].dir, directional_lights[i].dir);
02810     vec_normalize((float*)&cur_dlights[i].dir);
02811   }
02812 
02813 #if defined(VMDOPTIX_USE_HMD)
02814   HMDMgr *hmd = NULL;
02815   // if using HMD for display, get head tracking data
02816   if (getenv("VMDOPTIXUSEHMD") != NULL) {
02817     hmd = new HMDMgr();
02818     if (hmd->device_count() < 1) {
02819       delete hmd;
02820       hmd = NULL;
02821     }
02822   }
02823   if (hmd) {
02824     autosamplecount=0; // disable when targeting HMDs
02825     msgInfo << "OptiXRenderer) HMD in use, disabling auto sample count adjustement," << sendmsg;
02826     msgInfo << "OptiXRenderer) optimizing for lowest rendering latency." << sendmsg;
02827   }
02828 
02829 #if defined(VMDOPTIX_PROGRESSIVEAPI) 
02830   hmd_freerun = (hmd != NULL && camera_projection == RT_EQUIRECTANGULAR);
02831 #endif
02832 
02833 #if defined(VMDUSEEVENTIO)
02834   evio_handle eviodev = NULL;
02835   const char *eviodevname = getenv("VMDOPTIXEVIODEV");
02836   if (hmd && eviodevname) {
02837     msgInfo << "OptiXRenderer) Attempting to open '" 
02838             << eviodevname << "' for Linux event I/O input..." << sendmsg; 
02839     eviodev = evio_open(eviodevname);
02840     if (eviodev) {
02841       msgInfo << "OptiXRenderer) Using Linux event I/O input:" << sendmsg;
02842       evio_print_devinfo(eviodev);
02843     }
02844   }
02845 #endif
02846 #endif
02847 
02848   // create the display window
02849   const char *windowtitle;
02850 #if 1
02851   windowtitle = "VMD TachyonL-OptiX Interactive Ray Tracer";
02852 #else
02853   // useful for demos and perf comparisons
02854   if (getenv("VMDOPTIXNORTX") != NULL || rtx_enabled==0) {
02855     windowtitle = "VMD TachyonL-OptiX Interactive Ray Tracer -- Turing RTX DISABLED";
02856   } else {
02857     windowtitle = "VMD TachyonL-OptiX Interactive Ray Tracer -- Turing RTX ENABLED";
02858   }
02859 #endif
02860 
02861   void *win = createoptixwindow(windowtitle, width, height);
02862   interactive_viewer_usage(ctx, win);
02863   
02864   // check for stereo-capable display
02865   int havestereo=0, havestencil=0;
02866   int stereoon=0, stereoon_old=0;
02867   glwin_get_wininfo(win, &havestereo, &havestencil);
02868 
02869 #if defined(VMDOPTIX_USE_HMD) && defined(VMDOPTIX_PROGRESSIVEAPI)
02870   if (hmd_freerun && hmd != NULL && camera_projection == RT_EQUIRECTANGULAR) {
02871     glwin_spheremap_draw_prepare(win);
02872 
02873     // enable HMD optical distortion correction, unless force-disabled
02874     if (hmd != NULL && !getenv("VMDOPTIXHMDNOWARP"))
02875       hmd_warp = glwin_spheremap_create_hmd_warp(win, wsx, wsy, 21, 0,
02876                                                  width, height, hmd_warp_coeff);
02877 
02878     // if an HMD is in use, we trigger full-screen display by default
02879     if (hmd) {
02880       if (glwin_fullscreen(win, 1, 0) == 0) {
02881         gl_fs_on = 1;
02882         fsowsx = wsx;
02883         fsowsy = wsy;
02884         glwin_get_winsize(win, &wsx, &wsy);
02885       } else {
02886         printf("OptiXRenderer) Fullscreen mode not available\n");
02887       }
02888     }
02889   }
02890 #endif
02891 
02892   // Override AA/AO sample counts since we're doing progressive rendering.
02893   // Choosing an initial AO sample count of 1 will give us the peak progressive 
02894   // display update rate, but we end up wasting time on re-tracing many
02895   // primary rays.  The automatic FPS optimization scheme below will update
02896   // the number of samples per rendering pass and assign the best values for
02897   // AA/AO samples accordingly.
02898   cur_aa_samples = samples_per_pass;
02899   if (cur_ao_samples > 0) {
02900     cur_aa_samples = 1;
02901     cur_ao_samples = samples_per_pass;
02902   }
02903 
02904   const char *statestr = "|/-\\.";
02905   int done=0, winredraw=1;
02906   int state=0, mousedownx=0, mousedowny=0;
02907   float cur_cam_zoom = cam_zoom_orig;
02908 
02909   double fpsexpave=0.0; 
02910   double hmdfpsexpave=0.0;
02911   double hmdgldrawtime=0.0;
02912   double mapbuftotaltime=0.0;
02913   double accumbufstarttime=wkf_timer_timenow(ort_timer); 
02914   double oldtime = wkf_timer_timenow(ort_timer);
02915 #if defined(VMDOPTIX_USE_HMD)
02916   double hmdoldtime = oldtime;
02917 #endif
02918   while (!done) { 
02919     int winevent=0;
02920 
02921 #if 1
02922     if (app->uivs && app->uivs->srv_connected()) {
02923       if (app->uivs->srv_check_ui_event()) {
02924         int eventtype;
02925         app->uivs->srv_get_last_event_type(eventtype);
02926         switch (eventtype) {
02927           case VideoStream::VS_EV_ROTATE_BY:
02928             { int axis;
02929               float angle;
02930               app->uivs->srv_get_last_rotate_by(angle, axis);
02931               Matrix4 rm;
02932 
02933               switch (axis) {
02934                 case 'x':
02935                   rm.rotate_axis(cam_U, -angle * VMD_PI/180.0f);
02936                   break;
02937 
02938                 case 'y':
02939                   rm.rotate_axis(cam_V, -angle * VMD_PI/180.0f);
02940                   break;
02941 
02942                 case 'z':
02943                   rm.rotate_axis(cam_W, -angle * VMD_PI/180.0f);
02944                   break;
02945               }
02946               rm.multpoint3d(cam_pos, cam_pos);
02947               rm.multnorm3d(cam_U, cam_U);
02948               rm.multnorm3d(cam_V, cam_V);
02949               rm.multnorm3d(cam_W, cam_W);
02950 
02951               if (xformgradientsphere) {
02952                 rm.multnorm3d(scene_gradient, scene_gradient);
02953               }
02954 
02955               if (xformlights) {
02956                 // update light directions (comparatively costly)
02957                 for (i=0; i<directional_lights.num(); i++) {
02958                   rm.multnorm3d((float*)&cur_dlights[i].dir, (float*)&cur_dlights[i].dir);
02959                 }
02960               }
02961               winredraw = 1;
02962             }
02963             break;
02964 
02965           case VideoStream::VS_EV_TRANSLATE_BY:
02966             {
02967               float dU[3], dV[3], dW[3];
02968               float tx, ty, tz;
02969               app->uivs->srv_get_last_translate_by(tx, ty, tz);
02970               vec_scale(dU, -tx, cam_U);
02971               vec_scale(dV, -ty, cam_V);
02972               vec_scale(dW, -tz, cam_W);
02973               vec_add(cam_pos, cam_pos, dU);
02974               vec_add(cam_pos, cam_pos, dV);
02975               vec_add(cam_pos, cam_pos, dW);
02976               winredraw = 1;
02977             }
02978             break;
02979 
02980           case VideoStream::VS_EV_SCALE_BY:
02981             { float zoominc;
02982               app->uivs->srv_get_last_scale_by(zoominc);
02983               cam_zoom *= 1.0f / zoominc;
02984               winredraw = 1;
02985             }
02986             break;
02987 
02988 #if 0
02989               } else if (mm == RTMM_DOF) {
02990                 cam_dof_fnumber += txdx * 20.0f;
02991                 if (cam_dof_fnumber < 1.0f) cam_dof_fnumber = 1.0f;
02992                 cam_dof_focal_dist += -txdy;
02993                 if (cam_dof_focal_dist < 0.01f) cam_dof_focal_dist = 0.01f;
02994                 winredraw = 1;
02995               }
02996             }
02997 #endif
02998 
02999           case VideoStream::VS_EV_NONE: 
03000                   default:
03001             // should never happen...
03002             break;
03003         }
03004       }
03005     }              
03006 #endif
03007 
03008 
03009     while ((winevent = glwin_handle_events(win, GLWIN_EV_POLL_NONBLOCK)) != 0) {
03010       int evdev, evval;
03011       char evkey;
03012 
03013       glwin_get_lastevent(win, &evdev, &evval, &evkey);
03014       glwin_get_winsize(win, &wsx, &wsy);
03015 
03016       if (evdev == GLWIN_EV_WINDOW_CLOSE) {
03017         printf("OptiXRenderer) display window closed, exiting...\n");
03018         done = 1;
03019         winredraw = 0;
03020       } else if (evdev == GLWIN_EV_KBD) {
03021         switch (evkey) {
03022           case '`': autosamplecount=0; samples_per_pass=1; 
03023                     force_ao_1 = (!force_ao_1); winredraw=1; 
03024                     printf("OptiXRenderer) Toggling forced single AO sample per pass: %s\n",
03025                            force_ao_1 ? "on" : "off");
03026                     break;
03027 
03028           // update HMD warp distortion coefficients
03029           case '|': hmd_warp_coeff_set = (hmd_warp_coeff_set + 1) % 3;
03030                    switch (hmd_warp_coeff_set) {
03031                      case 0: 
03032                        printf("\nDistortion correction: DK2 stock lens\n");
03033                        memcpy(hmd_warp_coeff, dk2_warp_coeff, 5*sizeof(float));
03034                        break;
03035 
03036                      case 1: 
03037                        printf("\nDistortion correction: DK2 w/ MSR lens\n");
03038                        memcpy(hmd_warp_coeff, msr_warp_coeff, 5*sizeof(float));
03039                        break;
03040 
03041                      case 2: 
03042                        printf("\nDistortion correction: User defined lens\n");
03043                        memcpy(hmd_warp_coeff, user_warp_coeff, 5*sizeof(float));
03044                        break;
03045                    }
03046                    printf("\nHMD warp coeff: %.3f, %.3f, %.3f, %.3f, %.3f\n", 
03047                           hmd_warp_coeff[0], hmd_warp_coeff[1], 
03048                           hmd_warp_coeff[2], hmd_warp_coeff[3],
03049                           hmd_warp_coeff[4]);
03050                    hmd_warp_coeff_update=1; winredraw=1; break;
03051                    break; 
03052 
03053           case '\\': hmd_warp_coeff_edit = (hmd_warp_coeff_edit + 1) % 5;
03054                     printf("\nHMD edit warp coeff: r^%d\n",hmd_warp_coeff_edit);
03055                     break; 
03056 
03057           case '[': hmd_warp_coeff[hmd_warp_coeff_edit]-=0.005; 
03058                     printf("\nHMD warp coeff: %.3f, %.3f, %.3f, %.3f, %.3f\n", 
03059                            hmd_warp_coeff[0], hmd_warp_coeff[1], 
03060                            hmd_warp_coeff[2], hmd_warp_coeff[3],
03061                            hmd_warp_coeff[4]);
03062                     memcpy(user_warp_coeff, hmd_warp_coeff, 5*sizeof(float));
03063                     hmd_warp_coeff_update=1; winredraw=1; break;
03064 
03065           case ']': hmd_warp_coeff[hmd_warp_coeff_edit]+=0.005; 
03066                     printf("\nHMD warp coeff: %.3f, %.3f, %.3f, %.3f, %.3f\n", 
03067                            hmd_warp_coeff[0], hmd_warp_coeff[1], 
03068                            hmd_warp_coeff[2], hmd_warp_coeff[3],
03069                            hmd_warp_coeff[4]);
03070                     memcpy(user_warp_coeff, hmd_warp_coeff, 5*sizeof(float));
03071                     hmd_warp_coeff_update=1; winredraw=1; break;
03072 
03073           // update sample counts
03074           case  '1': autosamplecount=0; samples_per_pass=1; winredraw=1; break;
03075           case  '2': autosamplecount=0; samples_per_pass=2; winredraw=1; break;
03076           case  '3': autosamplecount=0; samples_per_pass=3; winredraw=1; break;
03077           case  '4': autosamplecount=0; samples_per_pass=4; winredraw=1; break;
03078           case  '5': autosamplecount=0; samples_per_pass=5; winredraw=1; break;
03079           case  '6': autosamplecount=0; samples_per_pass=6; winredraw=1; break;
03080           case  '7': autosamplecount=0; samples_per_pass=7; winredraw=1; break;
03081           case  '8': autosamplecount=0; samples_per_pass=8; winredraw=1; break;
03082           case  '9': autosamplecount=0; samples_per_pass=9; winredraw=1; break;
03083           case  '0': autosamplecount=0; samples_per_pass=10; winredraw=1; break;
03084 
03085           case  '=': /* recover back to initial state */
03086             vec_copy(scene_gradient, scene_gradient_orig);
03087             cam_zoom = cam_zoom_orig;
03088             vec_copy(cam_pos, cam_pos_orig);
03089             vec_copy(cam_U, cam_U_orig);
03090             vec_copy(cam_V, cam_V_orig);
03091             vec_copy(cam_W, cam_W_orig);
03092 
03093             // restore original light directions
03094             for (i=0; i<directional_lights.num(); i++) {
03095               vec_copy((float*)&cur_dlights[i].dir, directional_lights[i].dir);
03096               vec_normalize((float*)&cur_dlights[i].dir);
03097             }
03098             winredraw = 1;
03099 #if defined(VMDOPTIX_USE_HMD)
03100             // Handle HMD head orientation updates if we have one attached
03101             if (hmd) {
03102               hmd->reset_orientation();
03103               printf("\nOptiXRenderer) Resetting HMD orientation\n");
03104             }
03105 #endif
03106             break;
03107  
03108           case  ' ': /* spacebar saves current image with counter */
03109             {
03110               char snapfilename[256];
03111               sprintf(snapfilename, "vmdsnapshot.%04d.tga", snapshotcount);
03112               if (OptiXWriteImage(snapfilename, writealpha, framebuffer) != -1) {
03113                 printf("OptiXRenderer) Saved snapshot to '%s'             \n",
03114                        snapfilename);
03115               }
03116               snapshotcount++; 
03117             }
03118             break;
03119 
03120           case  'a': /* toggle automatic sample count FPS tuning */
03121             autosamplecount = !(autosamplecount);
03122             printf("\nOptiXRenderer) Automatic AO sample count FPS tuning %s\n",
03123                    (autosamplecount) ? "enabled" : "disabled");
03124             break;
03125 
03126           case  'f': /* DoF mode */
03127             mm = RTMM_DOF;
03128             printf("\nOptiXRenderer) Mouse DoF aperture and focal dist. mode\n");
03129             break;
03130 
03131           case  'g': /* toggle gradient sky sphere xforms */
03132             xformgradientsphere = !(xformgradientsphere);
03133             printf("\nOptiXRenderer) Gradient sky sphere transformations %s\n",
03134                    (xformgradientsphere) ? "enabled" : "disabled");
03135             break;
03136 
03137           case  'h': /* print help message */
03138             printf("\n");
03139             interactive_viewer_usage(ctx, win);
03140 
03141             // we have to force a redraw after querying OptiX context
03142             // info due to the current behavior of the progressive API,
03143             // which halts upon any API call other than the simplest queries
03144             winredraw = 1; 
03145             break;
03146 
03147           case  'l': /* toggle lighting xforms */
03148             xformlights = !(xformlights);
03149             printf("\nOptiXRenderer) Light transformations %s\n",
03150                    (xformlights) ? "enabled" : "disabled");
03151             break;
03152 
03153           case  'p': /* print current RT settings */
03154             printf("\nOptiXRenderer) Current Ray Tracing Parameters:\n"); 
03155             printf("OptiXRenderer) -------------------------------\n"); 
03156             printf("OptiXRenderer) Camera zoom: %f\n", cur_cam_zoom);
03157             printf("OptiXRenderer) Shadows: %s  Ambient occlusion: %s\n",
03158                    (gl_shadows_on) ? "on" : "off",
03159                    (gl_ao_on) ? "on" : "off");
03160             printf("OptiXRenderer) Antialiasing samples per-pass: %d\n",
03161                    cur_aa_samples);
03162             printf("OptiXRenderer) Ambient occlusion samples per-pass: %d\n",
03163                    cur_ao_samples);
03164             printf("OptiXRenderer) Depth-of-Field: %s f/num: %.1f  Foc. Dist: %.2f\n",
03165                    (gl_dof_on) ? "on" : "off", 
03166                    cam_dof_fnumber, cam_dof_focal_dist);
03167             printf("OptiXRenderer)   Win size: %d x %d\n", wsx, wsy);
03168             printf("OptiXRenderer) Image size: %d x %d\n", width, height);
03169             break;
03170 
03171           case  'r': /* rotate mode */
03172             mm = RTMM_ROT;
03173             printf("\nOptiXRenderer) Mouse rotation mode\n");
03174             break;
03175 
03176           case  's': /* scaling mode */
03177             mm = RTMM_SCALE;
03178             printf("\nOptiXRenderer) Mouse scaling mode\n");
03179             break;
03180 
03181           case  'F': /* toggle live movie recording FPS (24, 30, 60) */
03182             if (movie_recording_enabled) {
03183               switch (movie_recording_fps) {
03184                 case 24: movie_recording_fps = 30; break;
03185                 case 30: movie_recording_fps = 60; break;
03186                 case 60:
03187                 default: movie_recording_fps = 24; break;
03188               }
03189               printf("\nOptiXRenderer) Movie recording FPS rate: %d\n", 
03190                      movie_recording_fps);
03191             } else {
03192               printf("\nOptiXRenderer) Movie recording not available.\n");
03193             }
03194             break;
03195 
03196           case  'R': /* toggle live movie recording mode on/off */
03197             if (movie_recording_enabled) {
03198               movie_recording_on = !(movie_recording_on);
03199               printf("\nOptiXRenderer) Movie recording %s\n",
03200                      (movie_recording_on) ? "STARTED" : "STOPPED");
03201               if (movie_recording_on) {
03202                 movie_recording_start_time = wkf_timer_timenow(ort_timer); 
03203                 movie_framecount = 0;
03204                 movie_lastframeindex = 0;
03205               } else {
03206                 printf("OptiXRenderer) Encode movie with:\n");
03207                 printf("OptiXRenderer)   ffmpeg -f image2 -i vmdlivemovie.%%05d.tga -c:v libx264 -profile:v baseline -level 3.0 -pix_fmt yuv420p -b:v 15000000 output.mp4\n");
03208               }
03209             } else {
03210               printf("\nOptiXRenderer) Movie recording not available.\n");
03211             }
03212             break;
03213 
03214           case  'S': /* toggle stereoscopic display mode */
03215             if (havestereo) {
03216               stereoon = (!stereoon);
03217               printf("\nOptiXRenderer) Stereoscopic display %s\n",
03218                      (stereoon) ? "enabled" : "disabled");
03219               winredraw = 1;
03220             } else {
03221               printf("\nOptiXRenderer) Stereoscopic display unavailable\n");
03222             }
03223             break;
03224  
03225           case  't': /* translation mode */
03226             mm = RTMM_TRANS;
03227             printf("\nOptiXRenderer) Mouse translation mode\n");
03228             break;
03229             
03230           case  'q': /* 'q' key */
03231           case  'Q': /* 'Q' key */
03232           case 0x1b: /* ESC key */
03233             printf("\nOptiXRenderer) Exiting on user input.               \n");
03234             done=1; /* exit from interactive RT window */
03235             break;
03236         }
03237       } else if (evdev != GLWIN_EV_NONE) {
03238         switch (evdev) {
03239           case GLWIN_EV_KBD_F1: /* turn shadows on/off */
03240 #if defined(USE_REVERSE_SHADOW_RAYS) && defined(USE_REVERSE_SHADOW_RAYS_DEFAULT)
03241             gl_shadows_on=(!gl_shadows_on) ? RT_SHADOWS_ON_REVERSE : RT_SHADOWS_OFF;
03242 #else
03243             gl_shadows_on=(!gl_shadows_on) ? RT_SHADOWS_ON : RT_SHADOWS_OFF;
03244             // gl_shadows_on = (!gl_shadows_on);
03245 #endif
03246 
03247             printf("\n");
03248 #if defined(USE_REVERSE_SHADOW_RAYS) && defined(USE_REVERSE_SHADOW_RAYS_DEFAULT)
03249             printf("OptiXRenderer) Shadows %s\n",
03250                    (gl_shadows_on) ? "enabled (reversal opt.)" : "disabled");
03251 #else
03252             printf("OptiXRenderer) Shadows %s\n",
03253                    (gl_shadows_on) ? "enabled" : "disabled");
03254 #endif
03255             winredraw = 1; 
03256             break;
03257 
03258           case GLWIN_EV_KBD_F2: /* turn AO on/off */
03259             gl_ao_on = (!gl_ao_on); 
03260             printf("\n");
03261             printf("OptiXRenderer) Ambient occlusion %s\n",
03262                    (gl_ao_on) ? "enabled" : "disabled");
03263             winredraw = 1; 
03264             break;
03265 
03266           case GLWIN_EV_KBD_F3: /* turn DoF on/off */
03267             gl_dof_on = (!gl_dof_on);
03268             printf("\n");
03269             printf("OptiXRenderer) Depth-of-field %s\n",
03270                    (gl_dof_on) ? "enabled" : "disabled");
03271             winredraw = 1;
03272             break;
03273 
03274           case GLWIN_EV_KBD_F4: /* turn fog/depth cueing on/off */
03275             gl_fog_on = (!gl_fog_on); 
03276             printf("\n");
03277             printf("OptiXRenderer) Depth cueing %s\n",
03278                    (gl_fog_on) ? "enabled" : "disabled");
03279             winredraw = 1; 
03280             break;
03281 
03282           case GLWIN_EV_KBD_F5: /* turn HMD/camera fade+clipping on/off */
03283             gl_clip_on = (!gl_clip_on);
03284             printf("\n");
03285             printf("OptiXRenderer) HMD/camera clipping plane/sphere %s\n",
03286                    (gl_clip_on) ? "enabled" : "disabled");
03287             winredraw = 1; 
03288             break;
03289 
03290           case GLWIN_EV_KBD_F6: /* turn HMD/camera headlight on/off */
03291             gl_headlight_on = (!gl_headlight_on); 
03292             printf("\n");
03293             printf("OptiXRenderer) HMD/camera headlight %s\n",
03294                    (gl_headlight_on) ? "enabled" : "disabled");
03295             winredraw = 1; 
03296             break;
03297 
03298           case GLWIN_EV_KBD_F7: /* turn HMD draw interleaving on/off */
03299             hmd_interleave_draws = (!hmd_interleave_draws); 
03300             printf("\n");
03301             printf("OptiXRenderer) HMD interleaved draws %s\n",
03302                    (hmd_interleave_draws) ? "enabled" : "disabled");
03303             break;
03304 
03305           case GLWIN_EV_KBD_F8: /* turn HMD tex caching on/off */
03306             hmd_tex_caching = (!hmd_tex_caching); 
03307             printf("\n");
03308             printf("OptiXRenderer) HMD tex caching %s\n",
03309                    (hmd_tex_caching) ? "enabled" : "disabled");
03310             break;
03311 
03312           case GLWIN_EV_KBD_F9: /* switch HMD lens distortion correction mode */
03313             hmd_warp_drawmode = (hmd_warp_drawmode+1) % 5;
03314             printf("\n");
03315             { const char *warpmodestr="Off";
03316               switch (hmd_warp_drawmode) {
03317                 case 0: warpmodestr="Lens: Off  Chroma: Off  Grid: Off"; break;
03318                 case 1: warpmodestr="Lens: On   Chroma: On   Grid: Off"; break;
03319                 case 2: warpmodestr="Lens: On   Chroma: On   Grid: On "; break;
03320                 case 3: warpmodestr="Lens: On   Chroma: Off  Grid: Off"; break;
03321                 case 4: warpmodestr="Lens: On   Chroma: Off  Grid: On "; break;
03322               }
03323               printf("OptiXRenderer) HMD Corr.  %s\n", warpmodestr);
03324             }
03325             break;
03326 
03327 #ifdef USE_REVERSE_SHADOW_RAYS
03328           case GLWIN_EV_KBD_F10: /* toggle shadow ray reversal on/off */
03329             if (gl_shadows_on == RT_SHADOWS_ON) 
03330               gl_shadows_on = RT_SHADOWS_ON_REVERSE;
03331             else if (gl_shadows_on == RT_SHADOWS_ON_REVERSE)
03332               gl_shadows_on = RT_SHADOWS_ON;
03333             printf("\n");
03334             printf("OptiXRenderer) Shadow ray reversal %s\n",
03335                    (gl_shadows_on==RT_SHADOWS_ON_REVERSE) ? "enabled" : "disabled");
03336             winredraw = 1; 
03337             break;
03338 #endif
03339 
03340           case GLWIN_EV_KBD_F12: /* toggle full-screen window on/off */
03341             gl_fs_on = (!gl_fs_on);
03342             printf("\nOptiXRenderer) Toggling fullscreen window %s\n",
03343                    (gl_fs_on) ? "on" : "off");
03344             if (gl_fs_on) { 
03345               if (glwin_fullscreen(win, gl_fs_on, 0) == 0) {
03346                 fsowsx = wsx;
03347                 fsowsy = wsy;
03348                 glwin_get_winsize(win, &wsx, &wsy);
03349               } else {
03350                 printf("OptiXRenderer) Fullscreen mode note available\n");
03351               }
03352             } else {
03353               glwin_fullscreen(win, gl_fs_on, 0);
03354               glwin_resize(win, fsowsx, fsowsy);
03355             }
03356             winredraw = 1; 
03357             break;
03358 
03359           case GLWIN_EV_KBD_UP: /* change depth-of-field focal dist */
03360             cam_dof_focal_dist *= 1.02f; 
03361             printf("\nOptiXRenderer) DoF focal dist: %f\n", cam_dof_focal_dist);
03362             winredraw = 1; 
03363             break;
03364 
03365           case GLWIN_EV_KBD_DOWN: /* change depth-of-field focal dist */
03366             cam_dof_focal_dist *= 0.96f; 
03367             if (cam_dof_focal_dist < 0.02f) cam_dof_focal_dist = 0.02f;
03368             printf("\nOptiXRenderer) DoF focal dist: %f\n", cam_dof_focal_dist);
03369             winredraw = 1; 
03370             break;
03371 
03372           case GLWIN_EV_KBD_RIGHT: /* change depth-of-field f/stop number */
03373             cam_dof_fnumber += 1.0f; 
03374             printf("\nOptiXRenderer) DoF f/stop: %f\n", cam_dof_fnumber);
03375             winredraw = 1; 
03376             break;
03377 
03378           case GLWIN_EV_KBD_LEFT: /* change depth-of-field f/stop number */
03379             cam_dof_fnumber -= 1.0f; 
03380             if (cam_dof_fnumber < 1.0f) cam_dof_fnumber = 1.0f;
03381             printf("\nOptiXRenderer) DoF f/stop: %f\n", cam_dof_fnumber);
03382             winredraw = 1; 
03383             break;
03384 
03385           case GLWIN_EV_MOUSE_MOVE:
03386             if (mousedown != RTMD_NONE) {
03387               int x, y;
03388               glwin_get_mousepointer(win, &x, &y);
03389 
03390               float zoommod = 2.0f*cur_cam_zoom/cam_zoom_orig;
03391               float txdx = (x - mousedownx) * zoommod / wsx;
03392               float txdy = (y - mousedowny) * zoommod / wsy;
03393               if (mm != RTMM_SCALE) {
03394                 mousedownx = x;
03395                 mousedowny = y;
03396               }
03397 
03398               if (mm == RTMM_ROT) {
03399                 Matrix4 rm;
03400                 if (mousedown == RTMD_LEFT) {
03401                   // when zooming in further from the initial view, we
03402                   // rotate more slowly so control remains smooth
03403                   rm.rotate_axis(cam_V, -txdx);
03404                   rm.rotate_axis(cam_U, -txdy);
03405                 } else if (mousedown == RTMD_MIDDLE || 
03406                            mousedown == RTMD_RIGHT) {
03407                   rm.rotate_axis(cam_W, txdx);
03408                 }
03409                 rm.multpoint3d(cam_pos, cam_pos);
03410                 rm.multnorm3d(cam_U, cam_U);
03411                 rm.multnorm3d(cam_V, cam_V);
03412                 rm.multnorm3d(cam_W, cam_W);
03413 
03414                 if (xformgradientsphere) {
03415                   rm.multnorm3d(scene_gradient, scene_gradient);
03416                 }
03417  
03418                 if (xformlights) {
03419                   // update light directions (comparatively costly)
03420                   for (i=0; i<directional_lights.num(); i++) {
03421                     rm.multnorm3d((float*)&cur_dlights[i].dir, (float*)&cur_dlights[i].dir);
03422                   }
03423                 }
03424 
03425                 winredraw = 1;
03426               } else if (mm == RTMM_TRANS) {
03427                 if (mousedown == RTMD_LEFT) {
03428                   float dU[3], dV[3];
03429                   vec_scale(dU, -txdx, cam_U);
03430                   vec_scale(dV,  txdy, cam_V);
03431                   vec_add(cam_pos, cam_pos, dU); 
03432                   vec_add(cam_pos, cam_pos, dV); 
03433                 } else if (mousedown == RTMD_MIDDLE || 
03434                            mousedown == RTMD_RIGHT) {
03435                   float dW[3];
03436                   vec_scale(dW, txdx, cam_W);
03437                   vec_add(cam_pos, cam_pos, dW); 
03438                 } 
03439                 winredraw = 1;
03440               } else if (mm == RTMM_SCALE) {
03441                 float txdx = (x - mousedownx) * 2.0 / wsx;
03442                 float zoominc = 1.0f - txdx;
03443                 if (zoominc < 0.01f) zoominc = 0.01f;
03444                 cam_zoom = cur_cam_zoom * zoominc;
03445                 winredraw = 1;
03446               } else if (mm == RTMM_DOF) {
03447                 cam_dof_fnumber += txdx * 20.0f;
03448                 if (cam_dof_fnumber < 1.0f) cam_dof_fnumber = 1.0f;
03449                 cam_dof_focal_dist += -txdy; 
03450                 if (cam_dof_focal_dist < 0.01f) cam_dof_focal_dist = 0.01f;
03451                 winredraw = 1;
03452               }
03453             }
03454             break;
03455 
03456           case GLWIN_EV_MOUSE_LEFT:
03457           case GLWIN_EV_MOUSE_MIDDLE:
03458           case GLWIN_EV_MOUSE_RIGHT:
03459             if (evval) {
03460               glwin_get_mousepointer(win, &mousedownx, &mousedowny);
03461               cur_cam_zoom = cam_zoom;
03462 
03463               if (evdev == GLWIN_EV_MOUSE_LEFT) mousedown = RTMD_LEFT;
03464               else if (evdev == GLWIN_EV_MOUSE_MIDDLE) mousedown = RTMD_MIDDLE;
03465               else if (evdev == GLWIN_EV_MOUSE_RIGHT) mousedown = RTMD_RIGHT;
03466             } else {
03467               mousedown = RTMD_NONE;
03468             }
03469             break;
03470 
03471           case GLWIN_EV_MOUSE_WHEELUP:
03472             cam_zoom /= 1.1f; winredraw = 1; break;
03473 
03474           case GLWIN_EV_MOUSE_WHEELDOWN:
03475             cam_zoom *= 1.1f; winredraw = 1; break;
03476         }
03477       }
03478     }
03479 
03480 
03481     //
03482     // Support for Spaceball/Spacenavigator/Magellan devices that use
03483     // X11 ClientMessage protocol....
03484     //
03485     if (spaceballenabled) {
03486       // Spaceball/Spacenavigator/Magellan event state variables
03487       int tx=0, ty=0, tz=0, rx=0, ry=0, rz=0, buttons=0;
03488       if (glwin_get_spaceball(win, &rx, &ry, &rz, &tx, &ty, &tz, &buttons)) {
03489         // negate directions if we're in flight mode...
03490         if (spaceballflightmode) {
03491           rx= -rx;
03492           ry= -ry;
03493           rz= -rz;
03494 
03495           tx= -tx;
03496           ty= -ty;
03497           tz= -tz;
03498         }
03499 
03500         // check for button presses to reset the view
03501         if (buttons & 1) {
03502           printf("OptiXRenderer) spaceball button 1 pressed: reset view\n");
03503           vec_copy(scene_gradient, scene_gradient_orig);
03504           cam_zoom = cam_zoom_orig;
03505           vec_copy(cam_pos, cam_pos_orig);
03506           vec_copy(cam_U, cam_U_orig);
03507           vec_copy(cam_V, cam_V_orig);
03508           vec_copy(cam_W, cam_W_orig);
03509 
03510           // restore original light directions
03511           for (i=0; i<directional_lights.num(); i++) {
03512             vec_copy((float*)&cur_dlights[i].dir, directional_lights[i].dir);
03513             vec_normalize((float*)&cur_dlights[i].dir);
03514           }
03515           winredraw = 1;
03516         }
03517 
03518         // check for button presses to toggle spaceball mode
03519         if (buttons & 2) {
03520           spaceballmode = !(spaceballmode);
03521           printf("OptiXRenderer) spaceball mode: %s                        \n",
03522                  (spaceballmode) ? "scaling" : "rotation/translation");
03523         }
03524 
03525         // rotation/translation mode
03526         if (spaceballmode == 0) {
03527           float zoommod = 2.0f*cam_zoom/cam_zoom_orig;
03528           float divlen = sqrtf(wsx*wsx + wsy*wsy) * 50.0f;
03529 
03530           // check for rotation and handle it...
03531           if (rx != 0 || ry !=0 || rz !=0) {
03532             Matrix4 rm;
03533             rm.rotate_axis(cam_U, -rx * zoommod / divlen);
03534             rm.rotate_axis(cam_V, -ry * zoommod / divlen);
03535             rm.rotate_axis(cam_W, -rz * zoommod / divlen);
03536 
03537             rm.multpoint3d(cam_pos, cam_pos);
03538             rm.multnorm3d(cam_U, cam_U);
03539             rm.multnorm3d(cam_V, cam_V);
03540             rm.multnorm3d(cam_W, cam_W);
03541 
03542             if (xformgradientsphere) {
03543               rm.multnorm3d(scene_gradient, scene_gradient);
03544             }
03545 
03546             if (xformlights) {
03547               // update light directions (comparatively costly)
03548               for (i=0; i<directional_lights.num(); i++) {
03549                 rm.multnorm3d((float*)&cur_dlights[i].dir, (float*)&cur_dlights[i].dir);
03550               }
03551             }
03552             winredraw = 1;
03553           }
03554 
03555           // check for translation and handle it...
03556           if (tx != 0 || ty !=0 || tz !=0) {
03557             float dU[3], dV[3], dW[3];
03558             vec_scale(dU, -tx * zoommod / divlen, cam_U);
03559             vec_scale(dV, -ty * zoommod / divlen, cam_V);
03560             vec_scale(dW, -tz * zoommod / divlen, cam_W);
03561             vec_add(cam_pos, cam_pos, dU);
03562             vec_add(cam_pos, cam_pos, dV);
03563             vec_add(cam_pos, cam_pos, dW);
03564             winredraw = 1;
03565           }
03566         }
03567 
03568         // scaling mode
03569         if (spaceballmode == 1) {
03570           const float sbscale = 1.0f / (1024.0f * 8.0f);
03571           float zoominc = 1.0f - (rz * sbscale);
03572           if (zoominc < 0.01) zoominc = 0.01;
03573             cam_zoom *= zoominc;
03574             winredraw = 1;
03575         }
03576 
03577       }
03578     }
03579 
03580 
03581     // if there is no HMD, we use the camera orientation directly  
03582     vec_copy(hmd_U, cam_U);
03583     vec_copy(hmd_V, cam_V);
03584     vec_copy(hmd_W, cam_W);
03585 
03586     //
03587     // Handle HMD head orientation by directly manipulating the 
03588     // view orientation if we have an HMD attached and we're using
03589     // the direct-to-HMD "Oculus Rift" camera mode.  For the other 
03590     // equirectangular or cubemap cameras, the head pose processing
03591     // and all HMD lens aberration correction must done in the OpenGL 
03592     // display code rather than in the RT code itself.  When using the
03593     // direct-drive HMD camera, we only run a single rendering pass before
03594     // triggering a fresh orientation, since the head pose changes constantly.
03595     //
03596 #if defined(VMDOPTIX_USE_HMD)
03597     float hmd_U_new[3] = {1.0f, 0.0f, 0.0f};
03598     float hmd_V_new[3] = {0.0f, 1.0f, 0.0f};
03599     float hmd_W_new[3] = {0.0f, 0.0f, 1.0f};
03600 #if defined(VMDUSEEVENTIO)
03601     if ((hmd && eviodev) || (hmd && camera_projection == RT_OCULUS_RIFT)) {
03602 #else    
03603     if (hmd && camera_projection == RT_OCULUS_RIFT) {
03604 #endif
03605       float hmd_U_orig[3] = {1.0f, 0.0f, 0.0f};
03606       float hmd_V_orig[3] = {0.0f, 1.0f, 0.0f};
03607       float hmd_W_orig[3] = {0.0f, 0.0f, 1.0f};
03608 
03609       // query the HMD head pose as late as possible to reduce latency 
03610       // between the sensor reads and presentation on the display
03611       hmd->update();
03612       hmd->rot_basis_quat(hmd_U_new, hmd_V_new, hmd_W_new, 
03613                           hmd_U_orig, hmd_V_orig, hmd_W_orig);
03614 
03615       // We use the HMD pose quaternion to transform the standard camera
03616       // orientation basis vectors to their new orientation, and then we
03617       // project those onto the current view basis vector to get the 
03618       // correct final camera view vector that we pass along to OptiX
03619       float hmdtmp[3];
03620       memset(hmdtmp, 0, sizeof(hmdtmp));
03621       vec_scaled_add(hmdtmp, hmd_U_new[0], cam_U);
03622       vec_scaled_add(hmdtmp, hmd_U_new[1], cam_V);
03623       vec_scaled_add(hmdtmp, hmd_U_new[2], cam_W);
03624       vec_copy(hmd_U_new, hmdtmp);
03625 
03626       memset(hmdtmp, 0, sizeof(hmdtmp));
03627       vec_scaled_add(hmdtmp, hmd_V_new[0], cam_U);
03628       vec_scaled_add(hmdtmp, hmd_V_new[1], cam_V);
03629       vec_scaled_add(hmdtmp, hmd_V_new[2], cam_W);
03630       vec_copy(hmd_V_new, hmdtmp);
03631  
03632       memset(hmdtmp, 0, sizeof(hmdtmp));
03633       vec_scaled_add(hmdtmp, hmd_W_new[0], cam_U);
03634       vec_scaled_add(hmdtmp, hmd_W_new[1], cam_V);
03635       vec_scaled_add(hmdtmp, hmd_W_new[2], cam_W);
03636       vec_copy(hmd_W_new, hmdtmp);
03637 
03638 #if 0
03639       float q[4];
03640       hmd->get_rot_quat(q);
03641       printf("\nQ: %f %f %f %f\n", q[0], q[1], q[2], q[3]);
03642       printf("hmd_U: %.1f %.1f %.1f\n", hmd_U[0], hmd_U[1], hmd_U[2]);
03643       printf("hmd_V: %.1f %.1f %.1f\n", hmd_V[0], hmd_V[1], hmd_V[2]);
03644       printf("hmd_W: %.1f %.1f %.1f\n", hmd_W[0], hmd_W[1], hmd_W[2]);
03645 #endif
03646 
03647       if (hmd && camera_projection == RT_OCULUS_RIFT) {
03648         vec_copy(hmd_U, hmd_U_new);
03649         vec_copy(hmd_V, hmd_V_new);
03650         vec_copy(hmd_W, hmd_W_new);
03651 
03652         // when using an HMD in direct-drive mode, we have to do 
03653         // a redraw on every rendering pass.
03654         winredraw = 1;
03655       }
03656     }
03657 #endif
03658 
03659 
03660 #if defined(VMDUSEEVENTIO)
03661     //
03662     // Handle Linux event-based input device I/O for joysticks/spaceball/etc
03663     //
03664     if (eviodev) {
03665       float ax1, ay1, ax2, ay2;
03666       int buttons;
03667       int rc=0;
03668       rc = evio_get_joystick_status(eviodev, &ax1, &ay1, &ax2, &ay2, &buttons);
03669 
03670       if (buttons) {
03671         printf("Joystick: %5.2f %5.2f  %5.2f %5.2f  0x%08x  \n",
03672                ax1, ay1, ax2, ay2, buttons);
03673       }
03674 
03675       float tx = ax1 + ax2;
03676       float ty = ay1;
03677       float tz = ay2;
03678 
03679       // check for translation and handle it...
03680       if (fabsf(tx) > 0.03 || fabsf(ty) > 0.03 || fabsf(tz) > 0.03) { 
03681         tx *= -500;
03682         ty *=  500;
03683         tz *=  500;
03684 
03685         // Re-use the HMD head pose info obtained above to apply 
03686         // head motion translations from joysticks or other controllers
03687         float zoommod = 2.0f*cam_zoom/cam_zoom_orig;
03688         float divlen = sqrtf(wsx*wsx + wsy*wsy) * 50;
03689         float dU[3], dV[3], dW[3];
03690         vec_scale(dU, -tx * zoommod / divlen, hmd_U_new);
03691         vec_scale(dV, -ty * zoommod / divlen, hmd_V_new);
03692         vec_scale(dW, -tz * zoommod / divlen, hmd_W_new);
03693         vec_add(cam_pos, cam_pos, dU);
03694         vec_add(cam_pos, cam_pos, dV);
03695         vec_add(cam_pos, cam_pos, dW);
03696         winredraw = 1;
03697       }
03698 
03699     }
03700 #endif
03701 
03702 
03703     //
03704     // handle window resizing, stereoscopic mode changes,
03705     // destroy and recreate affected OptiX buffers
03706     //
03707     int resize_buffers=0;
03708 
03709 #if defined(VMDOPTIX_USE_HMD)
03710     // when using spheremaps, we trigger redraw ops but we do not change
03711     // the spheremap image size 
03712     if (hmd_freerun) {
03713       if (wsx != owsx || wsy != owsy)
03714         winredraw=1;
03715     } 
03716     else
03717 #endif
03718     {
03719       // only process image/window resizing when not drawing spheremaps
03720       if (wsx != width) {
03721         width = wsx;
03722         resize_buffers=1;
03723       }
03724  
03725       if (wsy != height || (stereoon != stereoon_old)) {
03726         if (stereoon) {
03727           if (height != wsy * 2) {
03728             height = wsy * 2; 
03729             resize_buffers=1;
03730           }
03731         } else {
03732           height = wsy;
03733           resize_buffers=1;
03734         }
03735       }
03736     }
03737 
03738 
03739 // XXX Prior to OptiX 3.8, we had to manually stop progressive 
03740 //     mode before changing any OptiX state.
03741 #if defined(VMDOPTIX_PROGRESSIVEAPI) && OPTIX_VERSION < 3080
03742     // 
03743     // Check for all conditions that would require modifying OptiX state
03744     // and tell the VCA to stop progressive rendering before we modify 
03745     // the rendering state, 
03746     //
03747     if (done || winredraw || resize_buffers ||
03748         (stereoon != stereoon_old) || (gl_dof_on != gl_dof_on_old)) {
03749       // need to issue stop command before editing optix objects
03750       if (vcarunning) {
03751         rtContextStopProgressive(ctx);
03752         vcarunning=0;
03753       }
03754     }
03755 #endif
03756 
03757     // check if stereo mode or DoF mode changed, both cases
03758     // require changing the active color accumulation ray gen program
03759     if ((stereoon != stereoon_old) || (gl_dof_on != gl_dof_on_old)) {
03760       // when stereo mode changes, we have to regenerate the
03761       // the RNG, accumulation buffer, and framebuffer
03762       if (stereoon != stereoon_old) {
03763         resize_buffers=1;
03764       }
03765 
03766       // update stereo and DoF state
03767       stereoon_old = stereoon;
03768       gl_dof_on_old = gl_dof_on;
03769 
03770       // set the active color accumulation ray gen program based on the 
03771       // camera/projection mode, stereoscopic display mode, 
03772       // and depth-of-field state
03773       set_accum_raygen_pgm(camera_projection, stereoon, gl_dof_on);
03774     }
03775 
03776     if (resize_buffers) {
03777       framebuffer_resize(width, height);
03778 
03779       // when movie recording is enabled, print the window size as a guide
03780       // since the user might want to precisely control the size or 
03781       // aspect ratio for a particular movie format, e.g. 1080p, 4:3, 16:9
03782       if (movie_recording_enabled) {
03783         printf("\rOptiXRenderer) Window resize: %d x %d                               \n", width, height);
03784       }
03785 
03786       winredraw=1;
03787     }
03788 
03789     int frame_ready = 1; // Default to true for the non-VCA case
03790     unsigned int subframe_count = 1;
03791     if (!done) {
03792 #if defined(VMDOPTIX_USE_HMD)
03793       // update HMD lens distortion correction mesh and/or warp coefficients 
03794       if (hmd_warp && (winredraw || hmd_warp_coeff_update)) {
03795         glwin_spheremap_update_hmd_warp(win, hmd_warp, wsx, wsy, 21,
03796                                         width, height, hmd_warp_coeff,
03797                                         hmd_warp_coeff_update);
03798         hmd_warp_coeff_update=0;
03799       }
03800 #endif
03801 
03802       //
03803       // If the user interacted with the window in a meaningful way, we
03804       // need to update the OptiX rendering state, recompile and re-validate
03805       // the context, and then re-render...
03806       //
03807       if (winredraw) {
03808         // update camera parameters
03809         RTERR( rtVariableSet1f( cam_zoom_v, cam_zoom) );
03810         RTERR( rtVariableSet3fv( cam_pos_v, cam_pos) );
03811         RTERR( rtVariableSet3fv(   cam_U_v, hmd_U) );
03812         RTERR( rtVariableSet3fv(   cam_V_v, hmd_V) );
03813         RTERR( rtVariableSet3fv(   cam_W_v, hmd_W) );
03814         RTERR( rtVariableSet3fv(scene_gradient_v, scene_gradient) );
03815  
03816         // update shadow state 
03817         RTERR( rtVariableSet1i(shadows_enabled_v, gl_shadows_on) );
03818 
03819         // update depth cueing state
03820         RTERR( rtVariableSet1i(fog_mode_v, 
03821                  (int) (gl_fog_on) ? fog_mode : RT_FOG_NONE) );
03822 
03823         // update clipping sphere state
03824         RTERR( rtVariableSet1i(clipview_mode_v, 
03825                  (int) (gl_clip_on) ? clipview_mode : RT_CLIP_NONE) );
03826 
03827         // update headlight state 
03828         RTERR( rtVariableSet1i(headlight_mode_v, 
03829                  (int) (gl_headlight_on) ? RT_HEADLIGHT_ON : RT_HEADLIGHT_OFF) );
03830  
03831         // update/recompute DoF values 
03832         RTERR( rtVariableSet1f(cam_dof_focal_dist_v, cam_dof_focal_dist) );
03833         RTERR( rtVariableSet1f(cam_dof_aperture_rad_v, cam_dof_focal_dist / (2.0f * cam_zoom * cam_dof_fnumber)) );
03834 
03835         //
03836         // Update light directions in the OptiX light buffer or user object.
03837         // Only update when xformlights is set, otherwise we take a 
03838         // speed hit when using a remote VCA cluster for rendering.
03839         //
03840         // We only transform directional lights, since our positional lights
03841         // are normally affixed to the model coordinate system rather than 
03842         // the camera.
03843         //
03844         if (xformlights) {
03845 #if defined(VMDOPTIX_LIGHTUSEROBJS)
03846           DirectionalLightList dlights;
03847           memset(&dlights, 0, sizeof(DirectionalLightList) );
03848           dlights.num_lights = directional_lights.num();
03849           int dlcount = directional_lights.num();
03850           dlcount = (dlcount > DISP_LIGHTS) ? DISP_LIGHTS : dlcount;
03851           for (i=0; i<dlcount; i++) {
03852             //vec_copy( (float*)( &lights.dirs[i] ), cur_dlights[i].dir );
03853             dlights.dirs[i] = cur_dlights[i].dir;
03854           }
03855           RTERR( rtVariableSetUserData(dir_light_list_v, sizeof(DirectionalLightList), &dlights) );
03856 #else
03857           DirectionalLight *dlbuf;
03858           RTERR( rtBufferMap(dir_lightbuffer, (void **) &dlbuf) );
03859           for (i=0; i<directional_lights.num(); i++) {
03860             vec_copy((float*)&dlbuf[i].dir, (float*)&cur_dlights[i].dir);
03861           }
03862           RTERR( rtBufferUnmap(dir_lightbuffer) );
03863 #endif
03864         }
03865 
03866         // reset accumulation buffer 
03867         totalsamplecount=0;
03868 
03869         // 
03870         // Sample count updates and OptiX state must always remain in 
03871         // sync, so if we only update sample count state during redraw events,
03872         // that's the only time we should recompute the sample counts, since
03873         // they also affect normalization factors for the accumulation buffer
03874         // in the non-VCA case.
03875         //
03876 
03877         // Update sample counts to achieve target interactivity
03878         if (autosamplecount) {
03879           if (fpsexpave > 37)
03880             samples_per_pass++;
03881           else if (fpsexpave < 30) 
03882             samples_per_pass--;
03883     
03884           // clamp sample counts to a "safe" range
03885           if (samples_per_pass > 14)
03886             samples_per_pass=14;
03887           if (samples_per_pass < 1)
03888             samples_per_pass=1;
03889         } 
03890 
03891         // split samples per pass either among AA and AO, depending on
03892         // whether DoF and AO are enabled or not. 
03893         if (force_ao_1) {
03894           cur_aa_samples = samples_per_pass;
03895           cur_ao_samples = 1;
03896         } else if (gl_shadows_on && gl_ao_on) {
03897           if (gl_dof_on) {
03898             if (samples_per_pass < 4) {
03899               cur_aa_samples=samples_per_pass;
03900               cur_ao_samples=1;
03901             } else {
03902               int s = (int) sqrtf(samples_per_pass);
03903               cur_aa_samples=s;
03904               cur_ao_samples=s;
03905             }
03906           } else {
03907             cur_aa_samples=1;
03908             cur_ao_samples=samples_per_pass;
03909           }
03910         } else {
03911           cur_aa_samples=samples_per_pass;
03912           cur_ao_samples=0;
03913         }
03914 
03915         // update the current AA/AO sample counts since they may be changing if
03916         // FPS autotuning is enabled...
03917         RTERR( rtVariableSet1i(aa_samples_v, cur_aa_samples) );
03918 
03919         // observe latest AO enable/disable flag, and sample count
03920         if (gl_shadows_on && gl_ao_on) {
03921           RTERR( rtVariableSet1i(ao_samples_v, cur_ao_samples) );
03922         } else {
03923           cur_ao_samples = 0;
03924           RTERR( rtVariableSet1i(ao_samples_v, 0) );
03925         }
03926 
03927 #ifdef VMDOPTIX_PROGRESSIVEAPI
03928         RTERR( rtVariableSet1f(accum_norm_v, 1.0f / float(cur_aa_samples)) );
03929 #endif
03930 
03931         // updated cached copy of previous window dimensions so we can
03932         // trigger updates on HMD spheremaps and FBOs as necessary
03933         owsx = wsx;
03934         owsy = wsy;
03935       } 
03936 
03937 
03938       //
03939       // The non-VCA code path must handle the accumulation buffer 
03940       // for itself, correctly rescaling the accumulated samples when
03941       // drawing to the output framebuffer.  
03942       //
03943       // The VCA code path takes care of normalization for itself.
03944       //
03945 #ifndef VMDOPTIX_PROGRESSIVEAPI
03946       // The accumulation buffer normalization factor must be updated
03947       // to reflect the total accumulation count before the accumulation
03948       // buffer is drawn to the output framebuffer
03949       RTERR( rtVariableSet1f(accum_norm_v, 1.0f / float(cur_aa_samples + accum_count)) );
03950 
03951       // The accumulation buffer subframe index must be updated to ensure that
03952       // the RNGs for AA and AO get correctly re-seeded
03953       RTERR( rtVariableSet1ui(accum_count_v, accum_count) );
03954 
03955       // Force context compilation/validation
03956       // If no state has changed, there's no need to recompile/validate.
03957       // This call can be omitted since OptiX will do this automatically
03958       // at the next rtContextLaunchXXX() call.
03959 //      render_compile_and_validate();
03960 #endif
03961 
03962 
03963       //
03964       // run the renderer 
03965       //
03966       frame_ready = 1; // Default to true for the non-VCA case
03967       subframe_count = 1;
03968       if (lasterror == RT_SUCCESS) {
03969         if (winredraw) {
03970 #if defined(ORT_RAYSTATS)
03971           RTERR( rtContextLaunch2D(ctx, RT_RAY_GEN_CLEAR_RAYSTATS, width, height) );
03972           accumbufstarttime=wkf_timer_timenow(ort_timer);
03973 #endif
03974 #ifdef VMDOPTIX_PROGRESSIVEAPI
03975           // start the VCA doing progressive rendering...
03976           RTERR( rtContextLaunchProgressive2D(ctx, RT_RAY_GEN_ACCUMULATE, width, height, 0) );
03977 #else
03978           RTERR( rtContextLaunch2D(ctx, RT_RAY_GEN_CLEAR_ACCUMULATION_BUFFER, width, height) );
03979 #endif
03980           winredraw=0;
03981         }
03982 
03983 #ifdef VMDOPTIX_PROGRESSIVEAPI
03984         // Wait for the next frame to arrive
03985         RTERR( rtBufferGetProgressiveUpdateReady(framebuffer, &frame_ready, &subframe_count, 0) );
03986         if (frame_ready) 
03987           totalsamplecount = subframe_count * samples_per_pass;
03988 #else
03989         // iterate, adding to the accumulation buffer...
03990         RTERR( rtContextLaunch2D(ctx, RT_RAY_GEN_ACCUMULATE, width, height) );
03991         subframe_count++; // increment subframe index
03992         totalsamplecount += samples_per_pass;
03993         accum_count += cur_aa_samples;
03994 
03995         // copy the accumulation buffer image data to the framebuffer and
03996         // perform type conversion and normaliztion on the image data...
03997         RTERR( rtContextLaunch2D(ctx, RT_RAY_GEN_COPY_FINISH, width, height) );
03998 #endif
03999 
04000         if (lasterror == RT_SUCCESS) {
04001           if (frame_ready || hmd_freerun) {
04002             double bufnewtime = wkf_timer_timenow(ort_timer);
04003 
04004             // if an HMD is connected and one of the panoramic image formats
04005             // is in use, we use the appopriate OpenGL HMD viewer for the 
04006             // panoramic image format that's currently active, otherwise the
04007             // image is displayed as-is in a window.
04008 #if defined(VMDOPTIX_USE_HMD)
04009             if (hmd_freerun) {
04010               double hmdnewtime = wkf_timer_timenow(ort_timer);
04011               double hmdframetime = (hmdnewtime-hmdoldtime) + 0.00001f;
04012               hmdoldtime=hmdnewtime;
04013 
04014               // compute exponential moving average for exp(-1/10)
04015               double hmdframefps = 1.0f/hmdframetime;
04016               hmdfpsexpave = (hmdfpsexpave * 0.90) + (hmdframefps * 0.10);
04017 
04018               float hmdquat[4];
04019               if (hmd_no_draw == 0) {
04020                 int hmd_warp_on = (hmd_warp_drawmode!=0);
04021                 int hmd_warp_lines = (hmd_warp_drawmode==2 || hmd_warp_drawmode==4);
04022                 int hmd_chroma_on = (hmd_warp_drawmode==1 || hmd_warp_drawmode==2);
04023 
04024                 // update when frame is ready, or when tex caching is disabled
04025                 if (frame_ready || (!hmd_tex_caching)) {
04026                   // display output image
04027                   const unsigned char * img;
04028                   rtBufferMap(framebuffer, (void **) &img);
04029 
04030                   // minimize impact of OptiX buffer map and tex update steps
04031                   if (hmd_interleave_draws) {
04032                     // query HMD sensors immediately prior to draw...
04033                     hmd->get_rot_quat(hmdquat, 1);
04034                     if (hmd_warp && hmd_warp_drawmode != 0) {
04035                       glwin_spheremap_draw_hmd_warp(win, hmd_warp, 
04036                           hmd_warp_on, hmd_warp_lines, hmd_chroma_on,
04037                           wsx, wsy, width, height, hmdquat, hmd_fov, 15.0f, hmd_spres);
04038                     } else {
04039                       glwin_spheremap_draw_tex(win, GLWIN_STEREO_OVERUNDER, width, height, hmdquat, hmd_fov, 15.0f, hmd_spres);
04040                     }
04041                     glwin_swap_buffers(win);
04042                   }
04043 
04044                   glwin_spheremap_upload_tex_rgb3u(win, width, height, img);
04045 
04046                   // minimize impact of OptiX buffer map and tex update steps
04047                   if (hmd_interleave_draws) {
04048                     // query HMD sensors immediately prior to draw...
04049                     hmd->get_rot_quat(hmdquat, 1);
04050                     if (hmd_warp && hmd_warp_drawmode != 0) {
04051                       glwin_spheremap_draw_hmd_warp(win, hmd_warp, 
04052                           hmd_warp_on, hmd_warp_lines, hmd_chroma_on,
04053                           wsx, wsy, width, height, hmdquat, hmd_fov, 15.0f, hmd_spres);
04054                     } else {
04055                       glwin_spheremap_draw_tex(win, GLWIN_STEREO_OVERUNDER, width, height, hmdquat, hmd_fov, 15.0f, hmd_spres);
04056                     }
04057                     glwin_swap_buffers(win);
04058                   }
04059  
04060                   rtBufferUnmap(framebuffer);
04061                   mapbuftotaltime = wkf_timer_timenow(ort_timer) - bufnewtime;
04062                 }
04063 
04064                 // query HMD sensors immediately prior to draw...
04065                 hmd->get_rot_quat(hmdquat, 1);
04066                 if (hmd_warp && hmd_warp_drawmode != 0) {
04067                   glwin_spheremap_draw_hmd_warp(win, hmd_warp, 
04068                       hmd_warp_on, hmd_warp_lines, hmd_chroma_on,
04069                       wsx, wsy, width, height, hmdquat, hmd_fov, 15.0f, hmd_spres);
04070                 } else {
04071                   glwin_spheremap_draw_tex(win, GLWIN_STEREO_OVERUNDER, width, height, hmdquat, hmd_fov, 15.0f, hmd_spres);
04072                 }
04073                 glwin_swap_buffers(win);
04074               }
04075 
04076               hmdgldrawtime = wkf_timer_timenow(ort_timer) - hmdnewtime;
04077             } else {
04078 #endif
04079               // display output image
04080               const unsigned char * img;
04081               rtBufferMap(framebuffer, (void **) &img);
04082 
04083 #if 0
04084               glwin_draw_image_tex_rgb3u(win, (stereoon!=0)*GLWIN_STEREO_OVERUNDER, width, height, img);
04085 #else
04086               glwin_draw_image_rgb3u(win, (stereoon!=0)*GLWIN_STEREO_OVERUNDER, width, height, img);
04087 #endif
04088 
04089 #if 1
04090               // push latest frame into the video streaming pipeline
04091               // and pump the event handling mechanism afterwards
04092               if (app->uivs && app->uivs->srv_connected()) {
04093                 app->uivs->video_frame_pending(img, width, height);             
04094                 app->uivs->check_event();             
04095               }              
04096 #endif
04097 
04098               rtBufferUnmap(framebuffer);
04099               mapbuftotaltime = wkf_timer_timenow(ort_timer) - bufnewtime;
04100 
04101 #if defined(VMDOPTIX_USE_HMD)
04102             }
04103 #endif
04104 
04105 
04106             // if live movie recording is on, we save every displayed frame
04107             // to a sequence sequence of image files, with each file numbered
04108             // by its frame index, which is computed by the multiplying image 
04109             // presentation time by the image sequence fixed-rate-FPS value.
04110             if (movie_recording_enabled && movie_recording_on) {
04111               char moviefilename[2048];
04112 
04113               // compute frame number from wall clock time and the
04114               // current fixed-rate movie playback frame rate
04115               double now = wkf_timer_timenow(ort_timer);
04116               double frametime = now - movie_recording_start_time;
04117               int fidx = frametime * movie_recording_fps;
04118 
04119               // always force the first recorded frame to be 0
04120               if (movie_framecount==0)
04121                 fidx=0;
04122               movie_framecount++;
04123 
04124 #if defined(__linux)
04125               // generate symlinks for frame indices between the last written
04126               // frame and the current one so that video encoders such as
04127               // ffmpeg and mencoder can be fed the contiguous frame sequence
04128               // at a fixed frame rate, as they require
04129               sprintf(moviefilename, movie_recording_filebase, 
04130                       movie_lastframeindex);
04131               int symidx;
04132               for (symidx=movie_lastframeindex; symidx<fidx; symidx++) {
04133                 char symlinkfilename[2048];
04134                 sprintf(symlinkfilename, movie_recording_filebase, symidx);
04135                 if (symlink(moviefilename, symlinkfilename) < 0)
04136                   perror("symlink: ");
04137               }
04138 #endif
04139                
04140               // write the new movie frame               
04141               sprintf(moviefilename, movie_recording_filebase, fidx);
04142               if (OptiXWriteImage(moviefilename, writealpha, framebuffer,
04143                                   RT_FORMAT_UNSIGNED_BYTE4, width, height) == -1) {
04144                 movie_recording_on = 0;
04145                 printf("\n");
04146                 printf("OptiXRenderer) ERROR during writing image during movie recording!\n");
04147                 printf("OptiXRenderer) Movie recording STOPPED\n");
04148               }
04149 
04150               movie_lastframeindex = fidx; // update last frame index written
04151             }
04152           }
04153         } else {
04154           printf("OptiXRenderer) An error occured during rendering. Rendering is aborted.\n");
04155           done=1;
04156           break;
04157         }
04158       } else {
04159         printf("OptiXRenderer) An error occured in AS generation. Rendering is aborted.\n");
04160         done=1;
04161         break;
04162       }
04163     }
04164 
04165     if (!done && frame_ready) {
04166       double newtime = wkf_timer_timenow(ort_timer);
04167       double frametime = (newtime-oldtime) + 0.00001f;
04168       oldtime=newtime;
04169 
04170       // compute exponential moving average for exp(-1/10)
04171       double framefps = 1.0f/frametime;
04172       fpsexpave = (fpsexpave * 0.90) + (framefps * 0.10);
04173 
04174       if (hmd_freerun) {
04175         printf("OptiXRenderer) %c AA%2d AO%2d %5d tot RT FPS %.1f HMD FPS %.0f GL%.4f MB%.4f \r",
04176                statestr[state], cur_aa_samples, cur_ao_samples, 
04177                totalsamplecount, fpsexpave, 
04178                hmdfpsexpave, hmdgldrawtime, mapbuftotaltime);
04179       } else {
04180         printf("OptiXRenderer) %c AA:%2d AO:%2d, %4d tot RT FPS: %.1f  %.4f s/frame sf: %d  \r",
04181                statestr[state], cur_aa_samples, cur_ao_samples, 
04182                totalsamplecount, fpsexpave, frametime, subframe_count);
04183       }
04184 
04185       fflush(stdout);
04186       state = (state+1) & 3;
04187     }
04188 
04189   } // end of per-cycle event processing
04190 
04191   printf("\n");
04192 
04193   // write the output image upon exit...
04194   if (lasterror == RT_SUCCESS) {
04195 #if defined(ORT_RAYSTATS)
04196     double frametime = wkf_timer_timenow(ort_timer) - accumbufstarttime;
04197     OptiXPrintRayStats(raystats1_buffer, raystats2_buffer, frametime);
04198 #endif
04199 
04200     wkf_timer_start(ort_timer);
04201     OptiXWriteImage(filename, writealpha, framebuffer); // write output image
04202     wkf_timer_stop(ort_timer);
04203 
04204     if (verbose == RT_VERB_TIMING || verbose == RT_VERB_DEBUG) {
04205       printf("OptiXRenderer) image file I/O time: %f secs\n", wkf_timer_time(ort_timer));
04206     }
04207   }
04208 
04209 #if defined(VMDOPTIX_USE_HMD)
04210   // if using HMD for display, get head tracking data
04211   if (hmd) {
04212     delete hmd;
04213     hmd = NULL;
04214   }
04215 
04216   if (hmd_warp != NULL) {
04217     glwin_spheremap_destroy_hmd_warp(win, hmd_warp);
04218   }
04219 #endif
04220 
04221 #if defined(VMDUSEEVENTIO)
04222   if (eviodev) {
04223     evio_close(eviodev);
04224   }
04225 #endif
04226 
04227   glwin_destroy(win);
04228 }
04229 
04230 #endif
04231 
04232 
04233 
04234 void OptiXRenderer::render_to_videostream(const char *filename, int writealpha) {
04235   int i;
04236 
04237   if (!context_created)
04238     return;
04239 
04240   // flags to interactively enable/disable shadows, AO, DoF
04241 #if defined(USE_REVERSE_SHADOW_RAYS) && defined(USE_REVERSE_SHADOW_RAYS_DEFAULT)
04242   int gl_shadows_on=(shadows_enabled) ? RT_SHADOWS_ON_REVERSE : RT_SHADOWS_OFF;
04243 #else
04244   int gl_shadows_on=(shadows_enabled) ? RT_SHADOWS_ON : RT_SHADOWS_OFF;
04245 #endif
04246 
04247 //  int owsx=0, owsy=0; // last win size
04248   int gl_ao_on=(ao_samples > 0);
04249   int gl_dof_on, gl_dof_on_old;
04250   gl_dof_on=gl_dof_on_old=dof_enabled; 
04251   int gl_fog_on=(fog_mode != RT_FOG_NONE);
04252   int gl_clip_on=(clipview_mode != RT_CLIP_NONE);
04253   int gl_headlight_on=(headlight_mode != RT_HEADLIGHT_OFF);
04254 
04255   // Enable live recording of a session to a stream of image files indexed
04256   // by their display presentation time, mapped to the nearest frame index
04257   // in a fixed-frame-rate image sequence (e.g. 24, 30, or 60 FPS), 
04258   // to allow subsequent encoding into a standard movie format.
04259   // XXX this feature is disabled by default at present, to prevent people
04260   //     from accidentally turning it on during a live demo or the like
04261   int movie_recording_enabled = (getenv("VMDOPTIXLIVEMOVIECAPTURE") != NULL);
04262   int movie_recording_on = 0;
04263   double movie_recording_start_time = 0.0;
04264   int movie_recording_fps = 30;
04265   int movie_framecount = 0;
04266   int movie_lastframeindex = 0;
04267   const char *movie_recording_filebase = "vmdlivemovie.%05d.tga";
04268   if (getenv("VMDOPTIXLIVEMOVIECAPTUREFILEBASE"))
04269     movie_recording_filebase = getenv("VMDOPTIXLIVEMOVIECAPTUREFILEBASE");
04270 
04271   // total AA/AO sample count
04272   int totalsamplecount=0;
04273 
04274   // counter for snapshots of live image...
04275   //int snapshotcount=0;
04276 
04277   // flag to enable automatic AO sample count adjustment for FPS rate control
04278 #if defined(VMDOPTIX_PROGRESSIVEAPI)
04279 #if 1
04280   int autosamplecount=0; // leave disabled for now
04281 #else
04282   int autosamplecount=1; // works partially in current revs of progressive API
04283 #endif
04284 #else
04285   int autosamplecount=1;
04286 #endif
04287 
04288   // flag to enable transformation of lights and gradient sky sphere, 
04289   // so that they track camera orientation as they do in the VMD OpenGL display
04290   int xformlights=1, xformgradientsphere=1;
04291 
04292   //
04293   // allocate or reconfigure the framebuffer, accumulation buffer, 
04294   // and output streams required for progressive rendering, either
04295   // using the new progressive APIs, or using our own code.
04296   //
04297   // Unless overridden by environment variables, we use the incoming
04298   // window size parameters from VMD to initialize the RT image dimensions.
04299   // If image size is overridden, often when using HMDs, the incoming 
04300   // dims are window dims are used to size the GL window, but the image size
04301   // is set independently.
04302   int wsx=width, wsy=height;
04303   const char *imageszstr = getenv("VMDOPTIXIMAGESIZE");
04304   if (imageszstr) {
04305     if (sscanf(imageszstr, "%d %d", &width, &height) != 2) {
04306       width=wsx;
04307       height=wsy;
04308     } 
04309   } 
04310 
04311   framebuffer_config(width, height, 1);
04312 
04313   // prepare the majority of OptiX rendering state before we go into 
04314   // the interactive rendering loop
04315   update_rendering_state(1);
04316   render_compile_and_validate();
04317 
04318   // make a copy of state we're going to interactively manipulate,
04319   // so that we can recover to the original state on-demand
04320   int samples_per_pass = 1;
04321   int force_ao_1 = 0; // whether or not to force AO count per pass to 1
04322   int cur_aa_samples = aa_samples;
04323   int cur_ao_samples = ao_samples;
04324   float cam_zoom_orig = cam_zoom;
04325   float scene_gradient_orig[3] = {0.0f, 1.0f, 0.0f};
04326   vec_copy(scene_gradient_orig, scene_gradient);
04327 
04328   float cam_pos_orig[3] = {0.0f, 0.0f, 2.0f};
04329   float cam_U_orig[3] = {1.0f, 0.0f, 0.0f};
04330   float cam_V_orig[3] = {0.0f, 1.0f, 0.0f};
04331   float cam_W_orig[3] = {0.0f, 0.0f, -1.0f};
04332   float cam_pos[3], cam_U[3], cam_V[3], cam_W[3];
04333   float hmd_U[3], hmd_V[3], hmd_W[3];
04334 
04335   vec_copy(cam_pos, cam_pos_orig);
04336   vec_copy(cam_U, cam_U_orig);
04337   vec_copy(cam_V, cam_V_orig);
04338   vec_copy(cam_W, cam_W_orig);
04339 
04340   // copy light directions
04341   DirectionalLight *cur_dlights = (DirectionalLight *) calloc(1, directional_lights.num() * sizeof(DirectionalLight));
04342   for (i=0; i<directional_lights.num(); i++) {
04343     vec_copy((float*)&cur_dlights[i].dir, directional_lights[i].dir);
04344     vec_normalize((float*)&cur_dlights[i].dir);
04345   }
04346 
04347   // check for stereo-capable display
04348   //int havestereo=0, havestencil=0;
04349   int stereoon=0, stereoon_old=0;
04350   // glwin_get_wininfo(win, &havestereo, &havestencil);
04351 
04352   // Override AA/AO sample counts since we're doing progressive rendering.
04353   // Choosing an initial AO sample count of 1 will give us the peak progressive 
04354   // display update rate, but we end up wasting time on re-tracing many
04355   // primary rays.  The automatic FPS optimization scheme below will update
04356   // the number of samples per rendering pass and assign the best values for
04357   // AA/AO samples accordingly.
04358   cur_aa_samples = samples_per_pass;
04359   if (cur_ao_samples > 0) {
04360     cur_aa_samples = 1;
04361     cur_ao_samples = samples_per_pass;
04362   }
04363 
04364   const char *statestr = "|/-\\.";
04365   int done=0, winredraw=1;
04366   int state=0;
04367   //float cur_cam_zoom = cam_zoom_orig;
04368 
04369   double fpsexpave=0.0; 
04370   double accumbufstarttime=wkf_timer_timenow(ort_timer); 
04371   double oldtime = wkf_timer_timenow(ort_timer);
04372   // Note: we immediately terminate the rendering loop if
04373   //       the videostream server loses its client connection(s)
04374   while (!done &&
04375          app->uivs && app->uivs->srv_connected()) { 
04376 
04377 #if 1
04378     if (app->uivs && app->uivs->srv_connected()) {
04379       if (app->uivs->srv_check_ui_event()) {
04380         int eventtype;
04381         app->uivs->srv_get_last_event_type(eventtype);
04382         switch (eventtype) {
04383           case VideoStream::VS_EV_ROTATE_BY:
04384             { int axis;
04385               float angle;
04386               app->uivs->srv_get_last_rotate_by(angle, axis);
04387               Matrix4 rm;
04388 
04389               switch (axis) {
04390                 case 'x':
04391                   rm.rotate_axis(cam_U, -angle * VMD_PI/180.0f);
04392                   break;
04393 
04394                 case 'y':
04395                   rm.rotate_axis(cam_V, -angle * VMD_PI/180.0f);
04396                   break;
04397 
04398                 case 'z':
04399                   rm.rotate_axis(cam_W, -angle * VMD_PI/180.0f);
04400                   break;
04401               }
04402               rm.multpoint3d(cam_pos, cam_pos);
04403               rm.multnorm3d(cam_U, cam_U);
04404               rm.multnorm3d(cam_V, cam_V);
04405               rm.multnorm3d(cam_W, cam_W);
04406 
04407               if (xformgradientsphere) {
04408                 rm.multnorm3d(scene_gradient, scene_gradient);
04409               }
04410 
04411               if (xformlights) {
04412                 // update light directions (comparatively costly)
04413                 for (i=0; i<directional_lights.num(); i++) {
04414                   rm.multnorm3d((float*)&cur_dlights[i].dir, (float*)&cur_dlights[i].dir);
04415                 }
04416               }
04417               winredraw = 1;
04418             }
04419             break;
04420 
04421           case VideoStream::VS_EV_TRANSLATE_BY:
04422             {
04423               float dU[3], dV[3], dW[3];
04424               float tx, ty, tz;
04425               app->uivs->srv_get_last_translate_by(tx, ty, tz);
04426               vec_scale(dU, -tx, cam_U);
04427               vec_scale(dV, -ty, cam_V);
04428               vec_scale(dW, -tz, cam_W);
04429               vec_add(cam_pos, cam_pos, dU);
04430               vec_add(cam_pos, cam_pos, dV);
04431               vec_add(cam_pos, cam_pos, dW);
04432               winredraw = 1;
04433             }
04434             break;
04435 
04436           case VideoStream::VS_EV_SCALE_BY:
04437             { float zoominc;
04438               app->uivs->srv_get_last_scale_by(zoominc);
04439               cam_zoom *= 1.0f / zoominc;
04440               winredraw = 1;
04441             }
04442             break;
04443 
04444 #if 0
04445               } else if (mm == RTMM_DOF) {
04446                 cam_dof_fnumber += txdx * 20.0f;
04447                 if (cam_dof_fnumber < 1.0f) cam_dof_fnumber = 1.0f;
04448                 cam_dof_focal_dist += -txdy;
04449                 if (cam_dof_focal_dist < 0.01f) cam_dof_focal_dist = 0.01f;
04450                 winredraw = 1;
04451               }
04452             }
04453 #endif
04454           case VideoStream::VS_EV_KEYBOARD:
04455             { int keydev, keyval, shift_state;
04456               app->uivs->srv_get_last_keyboard(keydev, keyval, shift_state);
04457               switch (keydev) {
04458                 case DisplayDevice::WIN_KBD:
04459                   {
04460                     switch (keyval) {
04461                       // update sample counts
04462                       case  '1': autosamplecount=0; samples_per_pass=1; winredraw=1; break;
04463                       case  '2': autosamplecount=0; samples_per_pass=2; winredraw=1; break;
04464                       case  '3': autosamplecount=0; samples_per_pass=3; winredraw=1; break;
04465                       case  '4': autosamplecount=0; samples_per_pass=4; winredraw=1; break;
04466                       case  '5': autosamplecount=0; samples_per_pass=5; winredraw=1; break;
04467                       case  '6': autosamplecount=0; samples_per_pass=6; winredraw=1; break;
04468                       case  '7': autosamplecount=0; samples_per_pass=7; winredraw=1; break;
04469                       case  '8': autosamplecount=0; samples_per_pass=8; winredraw=1; break;
04470                       case  '9': autosamplecount=0; samples_per_pass=9; winredraw=1; break;
04471                       case  '0': autosamplecount=0; samples_per_pass=10; winredraw=1; break;
04472 
04473                       case  '=': /* recover back to initial state */
04474                         vec_copy(scene_gradient, scene_gradient_orig);
04475                         cam_zoom = cam_zoom_orig;
04476                         vec_copy(cam_pos, cam_pos_orig);
04477                         vec_copy(cam_U, cam_U_orig);
04478                         vec_copy(cam_V, cam_V_orig);
04479                         vec_copy(cam_W, cam_W_orig);
04480 
04481                         // restore original light directions
04482                         for (i=0; i<directional_lights.num(); i++) {
04483                           vec_copy((float*)&cur_dlights[i].dir, directional_lights[i].dir);
04484                           vec_normalize((float*)&cur_dlights[i].dir);
04485                         }
04486                         winredraw = 1;
04487                         break;
04488 
04489                       case  'q': /* 'q' key */
04490                       case  'Q': /* 'Q' key */
04491                         printf("\nOptiXRenderer) Exiting on user input.               \n");
04492                         done=1; /* exit from interactive RT window */
04493                         break;
04494                     }
04495                   }
04496                   break;
04497 
04498                 case DisplayDevice::WIN_KBD_ESCAPE:
04499                   printf("\nOptiXRenderer) Exiting on user input.               \n");
04500                   done=1; /* exit from interactive RT window */
04501                   break;
04502 
04503                 case DisplayDevice::WIN_KBD_F1:
04504 #if defined(USE_REVERSE_SHADOW_RAYS) && defined(USE_REVERSE_SHADOW_RAYS_DEFAULT)
04505                   gl_shadows_on=(!gl_shadows_on) ? RT_SHADOWS_ON_REVERSE : RT_SHADOWS_OFF;
04506 #else
04507                   gl_shadows_on=(!gl_shadows_on) ? RT_SHADOWS_ON : RT_SHADOWS_OFF;
04508                   // gl_shadows_on = (!gl_shadows_on);
04509 #endif
04510 
04511                   printf("\n");
04512 #if defined(USE_REVERSE_SHADOW_RAYS) && defined(USE_REVERSE_SHADOW_RAYS_DEFAULT)
04513                   printf("OptiXRenderer) Shadows %s\n",
04514                          (gl_shadows_on) ? "enabled (reversal opt.)" : "disabled");
04515 #else
04516                   printf("OptiXRenderer) Shadows %s\n",
04517                          (gl_shadows_on) ? "enabled" : "disabled");
04518 #endif
04519                   winredraw = 1;
04520                   break;
04521 
04522                 case DisplayDevice::WIN_KBD_F2:
04523                   gl_ao_on = (!gl_ao_on);
04524                   printf("\n");
04525                   printf("OptiXRenderer) Ambient occlusion %s\n",
04526                          (gl_ao_on) ? "enabled" : "disabled");
04527                   winredraw = 1;
04528                   break;
04529 
04530                 case DisplayDevice::WIN_KBD_F3:
04531                   gl_dof_on = (!gl_dof_on);
04532                   printf("\n");
04533                   printf("OptiXRenderer) Depth-of-field %s\n",
04534                          (gl_dof_on) ? "enabled" : "disabled");
04535                   winredraw = 1;
04536                   break;
04537               }
04538             }
04539             break;
04540 
04541           case VideoStream::VS_EV_NONE: 
04542                   default:
04543             // should never happen...
04544             break;
04545         }
04546       }
04547     }              
04548 #endif
04549 
04550     // if there is no HMD, we use the camera orientation directly  
04551     vec_copy(hmd_U, cam_U);
04552     vec_copy(hmd_V, cam_V);
04553     vec_copy(hmd_W, cam_W);
04554 
04555     //
04556     // handle window resizing, stereoscopic mode changes,
04557     // destroy and recreate affected OptiX buffers
04558     //
04559     int resize_buffers=0;
04560 
04561     {
04562       // only process image/window resizing when not drawing spheremaps
04563       if (wsx != width) {
04564         width = wsx;
04565         resize_buffers=1;
04566       }
04567  
04568       if (wsy != height || (stereoon != stereoon_old)) {
04569         if (stereoon) {
04570           if (height != wsy * 2) {
04571             height = wsy * 2; 
04572             resize_buffers=1;
04573           }
04574         } else {
04575           height = wsy;
04576           resize_buffers=1;
04577         }
04578       }
04579     }
04580 
04581 
04582 // XXX Prior to OptiX 3.8, we had to manually stop progressive 
04583 //     mode before changing any OptiX state.
04584 #if defined(VMDOPTIX_PROGRESSIVEAPI) && OPTIX_VERSION < 3080
04585     // 
04586     // Check for all conditions that would require modifying OptiX state
04587     // and tell the VCA to stop progressive rendering before we modify 
04588     // the rendering state, 
04589     //
04590     if (done || winredraw || resize_buffers ||
04591         (stereoon != stereoon_old) || (gl_dof_on != gl_dof_on_old)) {
04592       // need to issue stop command before editing optix objects
04593       if (vcarunning) {
04594         rtContextStopProgressive(ctx);
04595         vcarunning=0;
04596       }
04597     }
04598 #endif
04599 
04600     // check if stereo mode or DoF mode changed, both cases
04601     // require changing the active color accumulation ray gen program
04602     if ((stereoon != stereoon_old) || (gl_dof_on != gl_dof_on_old)) {
04603       // when stereo mode changes, we have to regenerate the
04604       // the RNG, accumulation buffer, and framebuffer
04605       if (stereoon != stereoon_old) {
04606         resize_buffers=1;
04607       }
04608 
04609       // update stereo and DoF state
04610       stereoon_old = stereoon;
04611       gl_dof_on_old = gl_dof_on;
04612 
04613       // set the active color accumulation ray gen program based on the 
04614       // camera/projection mode, stereoscopic display mode, 
04615       // and depth-of-field state
04616       set_accum_raygen_pgm(camera_projection, stereoon, gl_dof_on);
04617     }
04618 
04619     if (resize_buffers) {
04620       framebuffer_resize(width, height);
04621 
04622       // when movie recording is enabled, print the window size as a guide
04623       // since the user might want to precisely control the size or 
04624       // aspect ratio for a particular movie format, e.g. 1080p, 4:3, 16:9
04625       if (movie_recording_enabled) {
04626         printf("\rOptiXRenderer) Window resize: %d x %d                               \n", width, height);
04627       }
04628 
04629       winredraw=1;
04630     }
04631 
04632     int frame_ready = 1; // Default to true for the non-VCA case
04633     unsigned int subframe_count = 1;
04634     if (!done) {
04635       //
04636       // If the user interacted with the window in a meaningful way, we
04637       // need to update the OptiX rendering state, recompile and re-validate
04638       // the context, and then re-render...
04639       //
04640       if (winredraw) {
04641         // update camera parameters
04642         RTERR( rtVariableSet1f( cam_zoom_v, cam_zoom) );
04643         RTERR( rtVariableSet3fv( cam_pos_v, cam_pos) );
04644         RTERR( rtVariableSet3fv(   cam_U_v, hmd_U) );
04645         RTERR( rtVariableSet3fv(   cam_V_v, hmd_V) );
04646         RTERR( rtVariableSet3fv(   cam_W_v, hmd_W) );
04647         RTERR( rtVariableSet3fv(scene_gradient_v, scene_gradient) );
04648  
04649         // update shadow state 
04650         RTERR( rtVariableSet1i(shadows_enabled_v, gl_shadows_on) );
04651 
04652         // update depth cueing state
04653         RTERR( rtVariableSet1i(fog_mode_v, 
04654                  (int) (gl_fog_on) ? fog_mode : RT_FOG_NONE) );
04655 
04656         // update clipping sphere state
04657         RTERR( rtVariableSet1i(clipview_mode_v, 
04658                  (int) (gl_clip_on) ? clipview_mode : RT_CLIP_NONE) );
04659 
04660         // update headlight state 
04661         RTERR( rtVariableSet1i(headlight_mode_v, 
04662                  (int) (gl_headlight_on) ? RT_HEADLIGHT_ON : RT_HEADLIGHT_OFF) );
04663  
04664         // update/recompute DoF values 
04665         RTERR( rtVariableSet1f(cam_dof_focal_dist_v, cam_dof_focal_dist) );
04666         RTERR( rtVariableSet1f(cam_dof_aperture_rad_v, cam_dof_focal_dist / (2.0f * cam_zoom * cam_dof_fnumber)) );
04667 
04668         //
04669         // Update light directions in the OptiX light buffer or user object.
04670         // Only update when xformlights is set, otherwise we take a 
04671         // speed hit when using a remote VCA cluster for rendering.
04672         //
04673         // We only transform directional lights, since our positional lights
04674         // are normally affixed to the model coordinate system rather than 
04675         // the camera.
04676         //
04677         if (xformlights) {
04678 #if defined(VMDOPTIX_LIGHTUSEROBJS)
04679           DirectionalLightList dlights;
04680           memset(&dlights, 0, sizeof(DirectionalLightList) );
04681           dlights.num_lights = directional_lights.num();
04682           int dlcount = directional_lights.num();
04683           dlcount = (dlcount > DISP_LIGHTS) ? DISP_LIGHTS : dlcount;
04684           for (i=0; i<dlcount; i++) {
04685             //vec_copy( (float*)( &lights.dirs[i] ), cur_dlights[i].dir );
04686             dlights.dirs[i] = cur_dlights[i].dir;
04687           }
04688           RTERR( rtVariableSetUserData(dir_light_list_v, sizeof(DirectionalLightList), &dlights) );
04689 #else
04690           DirectionalLight *dlbuf;
04691           RTERR( rtBufferMap(dir_lightbuffer, (void **) &dlbuf) );
04692           for (i=0; i<directional_lights.num(); i++) {
04693             vec_copy((float*)&dlbuf[i].dir, (float*)&cur_dlights[i].dir);
04694           }
04695           RTERR( rtBufferUnmap(dir_lightbuffer) );
04696 #endif
04697         }
04698 
04699         // reset accumulation buffer 
04700         totalsamplecount=0;
04701 
04702         // 
04703         // Sample count updates and OptiX state must always remain in 
04704         // sync, so if we only update sample count state during redraw events,
04705         // that's the only time we should recompute the sample counts, since
04706         // they also affect normalization factors for the accumulation buffer
04707         // in the non-VCA case.
04708         //
04709 
04710         // Update sample counts to achieve target interactivity
04711         if (autosamplecount) {
04712           if (fpsexpave > 37)
04713             samples_per_pass++;
04714           else if (fpsexpave < 30) 
04715             samples_per_pass--;
04716     
04717           // clamp sample counts to a "safe" range
04718           if (samples_per_pass > 14)
04719             samples_per_pass=14;
04720           if (samples_per_pass < 1)
04721             samples_per_pass=1;
04722         } 
04723 
04724         // split samples per pass either among AA and AO, depending on
04725         // whether DoF and AO are enabled or not. 
04726         if (force_ao_1) {
04727           cur_aa_samples = samples_per_pass;
04728           cur_ao_samples = 1;
04729         } else if (gl_shadows_on && gl_ao_on) {
04730           if (gl_dof_on) {
04731             if (samples_per_pass < 4) {
04732               cur_aa_samples=samples_per_pass;
04733               cur_ao_samples=1;
04734             } else {
04735               int s = (int) sqrtf(samples_per_pass);
04736               cur_aa_samples=s;
04737               cur_ao_samples=s;
04738             }
04739           } else {
04740             cur_aa_samples=1;
04741             cur_ao_samples=samples_per_pass;
04742           }
04743         } else {
04744           cur_aa_samples=samples_per_pass;
04745           cur_ao_samples=0;
04746         }
04747 
04748         // update the current AA/AO sample counts since they may be changing if
04749         // FPS autotuning is enabled...
04750         RTERR( rtVariableSet1i(aa_samples_v, cur_aa_samples) );
04751 
04752         // observe latest AO enable/disable flag, and sample count
04753         if (gl_shadows_on && gl_ao_on) {
04754           RTERR( rtVariableSet1i(ao_samples_v, cur_ao_samples) );
04755         } else {
04756           cur_ao_samples = 0;
04757           RTERR( rtVariableSet1i(ao_samples_v, 0) );
04758         }
04759 
04760 #ifdef VMDOPTIX_PROGRESSIVEAPI
04761         RTERR( rtVariableSet1f(accum_norm_v, 1.0f / float(cur_aa_samples)) );
04762 #endif
04763 
04764         // updated cached copy of previous window dimensions so we can
04765         // trigger updates on HMD spheremaps and FBOs as necessary
04766         // owsx = wsx;
04767         // owsy = wsy;
04768       } 
04769 
04770 
04771       //
04772       // The non-VCA code path must handle the accumulation buffer 
04773       // for itself, correctly rescaling the accumulated samples when
04774       // drawing to the output framebuffer.  
04775       //
04776       // The VCA code path takes care of normalization for itself.
04777       //
04778 #ifndef VMDOPTIX_PROGRESSIVEAPI
04779       // The accumulation buffer normalization factor must be updated
04780       // to reflect the total accumulation count before the accumulation
04781       // buffer is drawn to the output framebuffer
04782       RTERR( rtVariableSet1f(accum_norm_v, 1.0f / float(cur_aa_samples + accum_count)) );
04783 
04784       // The accumulation buffer subframe index must be updated to ensure that
04785       // the RNGs for AA and AO get correctly re-seeded
04786       RTERR( rtVariableSet1ui(accum_count_v, accum_count) );
04787 
04788       // Force context compilation/validation
04789       // If no state has changed, there's no need to recompile/validate.
04790       // This call can be omitted since OptiX will do this automatically
04791       // at the next rtContextLaunchXXX() call.
04792 //      render_compile_and_validate();
04793 #endif
04794 
04795 
04796       //
04797       // run the renderer 
04798       //
04799       frame_ready = 1; // Default to true for the non-VCA case
04800       subframe_count = 1;
04801       if (lasterror == RT_SUCCESS) {
04802         if (winredraw) {
04803 #if defined(ORT_RAYSTATS)
04804           RTERR( rtContextLaunch2D(ctx, RT_RAY_GEN_CLEAR_RAYSTATS, width, height) );
04805           accumbufstarttime=wkf_timer_timenow(ort_timer);
04806 #endif
04807 #ifdef VMDOPTIX_PROGRESSIVEAPI
04808           // start the VCA doing progressive rendering...
04809           RTERR( rtContextLaunchProgressive2D(ctx, RT_RAY_GEN_ACCUMULATE, width, height, 0) );
04810 #else
04811           RTERR( rtContextLaunch2D(ctx, RT_RAY_GEN_CLEAR_ACCUMULATION_BUFFER, width, height) );
04812 #endif
04813           winredraw=0;
04814         }
04815 
04816 #ifdef VMDOPTIX_PROGRESSIVEAPI
04817         // Wait for the next frame to arrive
04818         RTERR( rtBufferGetProgressiveUpdateReady(framebuffer, &frame_ready, &subframe_count, 0) );
04819         if (frame_ready) 
04820           totalsamplecount = subframe_count * samples_per_pass;
04821 #else
04822         // iterate, adding to the accumulation buffer...
04823         RTERR( rtContextLaunch2D(ctx, RT_RAY_GEN_ACCUMULATE, width, height) );
04824         subframe_count++; // increment subframe index
04825         totalsamplecount += samples_per_pass;
04826         accum_count += cur_aa_samples;
04827 
04828         // copy the accumulation buffer image data to the framebuffer and
04829         // perform type conversion and normaliztion on the image data...
04830         RTERR( rtContextLaunch2D(ctx, RT_RAY_GEN_COPY_FINISH, width, height) );
04831 #endif
04832 
04833         if (lasterror == RT_SUCCESS) {
04834           if (frame_ready) {
04835             // display output image
04836             const unsigned char * img;
04837             rtBufferMap(framebuffer, (void **) &img);
04838 
04839 #if 1
04840             // push latest frame into the video streaming pipeline
04841             // and pump the event handling mechanism afterwards
04842             if (app->uivs && app->uivs->srv_connected()) {
04843               app->uivs->video_frame_pending(img, width, height);             
04844               app->uivs->check_event();             
04845             }              
04846 #endif
04847 
04848             rtBufferUnmap(framebuffer);
04849 
04850             // if live movie recording is on, we save every displayed frame
04851             // to a sequence sequence of image files, with each file numbered
04852             // by its frame index, which is computed by the multiplying image 
04853             // presentation time by the image sequence fixed-rate-FPS value.
04854             if (movie_recording_enabled && movie_recording_on) {
04855               char moviefilename[2048];
04856 
04857               // compute frame number from wall clock time and the
04858               // current fixed-rate movie playback frame rate
04859               double now = wkf_timer_timenow(ort_timer);
04860               double frametime = now - movie_recording_start_time;
04861               int fidx = frametime * movie_recording_fps;
04862 
04863               // always force the first recorded frame to be 0
04864               if (movie_framecount==0)
04865                 fidx=0;
04866               movie_framecount++;
04867 
04868 #if defined(__linux)
04869               // generate symlinks for frame indices between the last written
04870               // frame and the current one so that video encoders such as
04871               // ffmpeg and mencoder can be fed the contiguous frame sequence
04872               // at a fixed frame rate, as they require
04873               sprintf(moviefilename, movie_recording_filebase, 
04874                       movie_lastframeindex);
04875               int symidx;
04876               for (symidx=movie_lastframeindex; symidx<fidx; symidx++) {
04877                 char symlinkfilename[2048];
04878                 sprintf(symlinkfilename, movie_recording_filebase, symidx);
04879                 if (symlink(moviefilename, symlinkfilename) < 0)
04880                   perror("symlink: ");
04881               }
04882 #endif
04883                
04884               // write the new movie frame               
04885               sprintf(moviefilename, movie_recording_filebase, fidx);
04886               if (OptiXWriteImage(moviefilename, writealpha, framebuffer,
04887                                   RT_FORMAT_UNSIGNED_BYTE4, width, height) == -1) {
04888                 movie_recording_on = 0;
04889                 printf("\n");
04890                 printf("OptiXRenderer) ERROR during writing image during movie recording!\n");
04891                 printf("OptiXRenderer) Movie recording STOPPED\n");
04892               }
04893 
04894               movie_lastframeindex = fidx; // update last frame index written
04895             }
04896           }
04897         } else {
04898           printf("OptiXRenderer) An error occured during rendering. Rendering is aborted.\n");
04899           done=1;
04900           break;
04901         }
04902       } else {
04903         printf("OptiXRenderer) An error occured in AS generation. Rendering is aborted.\n");
04904         done=1;
04905         break;
04906       }
04907     }
04908 
04909     if (!done && frame_ready) {
04910       double newtime = wkf_timer_timenow(ort_timer);
04911       double frametime = (newtime-oldtime) + 0.00001f;
04912       oldtime=newtime;
04913 
04914       // compute exponential moving average for exp(-1/10)
04915       double framefps = 1.0f/frametime;
04916       fpsexpave = (fpsexpave * 0.90) + (framefps * 0.10);
04917 
04918       printf("OptiXRenderer) %c AA:%2d AO:%2d, %4d tot RT FPS: %.1f  %.4f s/frame sf: %d  \r",
04919              statestr[state], cur_aa_samples, cur_ao_samples, 
04920              totalsamplecount, fpsexpave, frametime, subframe_count);
04921 
04922       fflush(stdout);
04923       state = (state+1) & 3;
04924     }
04925 
04926   } // end of per-cycle event processing
04927 
04928   printf("\n");
04929 
04930   // write the output image upon exit...
04931   if (lasterror == RT_SUCCESS) {
04932 #if defined(ORT_RAYSTATS)
04933     double frametime = wkf_timer_timenow(ort_timer) - accumbufstarttime;
04934     OptiXPrintRayStats(raystats1_buffer, raystats2_buffer, frametime);
04935 #endif
04936 
04937     wkf_timer_start(ort_timer);
04938     OptiXWriteImage(filename, writealpha, framebuffer); // write output image
04939     wkf_timer_stop(ort_timer);
04940 
04941     if (verbose == RT_VERB_TIMING || verbose == RT_VERB_DEBUG) {
04942       printf("OptiXRenderer) image file I/O time: %f secs\n", wkf_timer_time(ort_timer));
04943     }
04944   }
04945 }
04946 
04947 
04948 void OptiXRenderer::render_to_file(const char *filename, int writealpha) {
04949   if (!context_created)
04950     return;
04951 
04952   // Unless overridden by environment variables, we use the incoming
04953   // window size parameters from VMD to initialize the RT image dimensions.
04954   int wsx=width, wsy=height;
04955   const char *imageszstr = getenv("VMDOPTIXIMAGESIZE");
04956   if (imageszstr) {
04957     if (sscanf(imageszstr, "%d %d", &width, &height) != 2) {
04958       width=wsx;
04959       height=wsy;
04960     }
04961   }
04962 
04963   // config/allocate framebuffer and accumulation buffer
04964   framebuffer_config(width, height, 0);
04965 
04966   update_rendering_state(0);
04967   render_compile_and_validate();
04968   double starttime = wkf_timer_timenow(ort_timer);
04969 
04970   //
04971   // run the renderer 
04972   //
04973   if (lasterror == RT_SUCCESS) {
04974 #if defined(ORT_RAYSTATS)
04975     RTERR( rtContextLaunch2D(ctx, RT_RAY_GEN_CLEAR_RAYSTATS, width, height) );
04976 #endif
04977     // clear the accumulation buffer
04978     RTERR( rtContextLaunch2D(ctx, RT_RAY_GEN_CLEAR_ACCUMULATION_BUFFER, width, height) );
04979 
04980     // Render to the accumulation buffer for the required number of passes
04981     if (getenv("VMDOPTIXNORENDER") == NULL) {
04982       int accum_sample;
04983       for (accum_sample=0; accum_sample<ext_aa_loops; accum_sample++) {
04984         // The accumulation subframe count must be updated to ensure that
04985         // the RNGs for AA and AO get correctly re-seeded
04986         RTERR( rtVariableSet1ui(accum_count_v, accum_sample) );
04987   
04988         RTERR( rtContextLaunch2D(ctx, RT_RAY_GEN_ACCUMULATE, width, height) );
04989       }
04990     }
04991 
04992     // copy the accumulation buffer image data to the framebuffer and perform
04993     // type conversion and normaliztion on the image data...
04994     RTERR( rtContextLaunch2D(ctx, RT_RAY_GEN_COPY_FINISH, width, height) );
04995     double rtendtime = wkf_timer_timenow(ort_timer);
04996     time_ray_tracing = rtendtime - starttime;
04997 
04998     if (lasterror == RT_SUCCESS) {
04999       // write output image to a file unless we are benchmarking
05000       if (getenv("VMDOPTIXNOSAVE") == NULL) {
05001         OptiXWriteImage(filename, writealpha, framebuffer);
05002       }
05003 #if defined(ORT_RAYSTATS)
05004       OptiXPrintRayStats(raystats1_buffer, raystats2_buffer, time_ray_tracing);
05005 #endif
05006       time_image_io = wkf_timer_timenow(ort_timer) - rtendtime;
05007     } else {
05008       printf("OptiXRenderer) Error during rendering.  Rendering aborted.\n");
05009     }
05010 
05011     if (verbose == RT_VERB_TIMING || verbose == RT_VERB_DEBUG) {
05012       printf("OptiXRenderer) ctx setup %.2f  valid %.2f  AS %.2f  RT %.2f io %.2f\n", time_ctx_setup, time_ctx_validate, time_ctx_AS_build, time_ray_tracing, time_image_io);
05013     }
05014   } else {
05015     printf("OptiXRenderer) Error during AS generation.  Rendering aborted.\n");
05016   }
05017 }
05018 
05019 
05020 #if defined(VMDOPTIXRTRT)
05021 
05022 void OptiXRenderer::add_material_cmdlist(const VMDDisplayList *cmdList) {
05023   add_material(cmdList->materialtag,
05024                cmdList->ambient,
05025                cmdList->diffuse,
05026                cmdList->specular,
05027                cmdList->shininess,
05028                cmdList->mirror,
05029                cmdList->opacity,
05030                cmdList->outline,
05031                cmdList->outlinewidth,
05032                cmdList->transmode);
05033 }
05034 
05035 
05036 void OptiXRenderer::scene_aggregate_cmdlist(const VMDDisplayList *cmdList,
05037                                             const float *colorData) {
05038 //  printf("OptiXRenderer) --> RTX RTRT Passthrough\n");
05039 
05040   char *cmdptr = NULL;  // ptr to current display command data
05041   int tok;              // what display command was encountered
05042 
05043   // early exit if any of these conditions are true.
05044   if (!cmdList)
05045     return;
05046 
05047   Stack<Matrix4> transMat(10);
05048   Matrix4 m;
05049   transMat.push(m);           // push on the identity matrix
05050   (transMat.top()).multmatrix(cmdList->mat);   // save transformation matrix
05051 
05052   // set up text matrices
05053 //  Matrix4 textMat(ogl_textMat);
05054 //  textMat.multmatrix(cmdList->mat);
05055 
05056 #if 0
05057   // enable/disable clipping planes
05058   for (int cp=0; cp<VMD_MAX_CLIP_PLANE; cp++) {
05059     // don't cache 'on' state since the parameters will likely differ,
05060     // just setup the clip plane from the new state
05061     if (cmdList->clipplanes[cp].mode) {
05062     }
05063   } 
05064 #endif
05065 
05066 #if 0
05067   // Compute periodic image transformation matrices
05068   ResizeArray<Matrix4> pbcImages;
05069   find_pbc_images(cmdList, pbcImages);
05070   int npbcimages = pbcImages.num();
05071 
05072   // Retreive instance image transformation matrices
05073   ResizeArray<Matrix4> instanceImages;
05074   find_instance_images(cmdList, instanceImages);
05075   int ninstances = instanceImages.num();
05076 
05077   for (int pbcimage = 0; pbcimage < npbcimages; pbcimage++) {
05078     transMat.dup();
05079     (transMat.top()).multmatrix(pbcImages[pbcimage]);
05080     for (int instanceimage = 0; instanceimage < ninstances; instanceimage++) {
05081       transMat.dup();
05082       (transMat.top()).multmatrix(instanceImages[instanceimage]);
05083     }
05084   }
05085 #endif 
05086 
05087 #if 0
05088   // find previously cached display list for this object
05089   if (ogl_cacheenabled && !ogl_cacheskip) {
05090     ogl_cachedid = displaylistcache.markUsed(cmdList->serial);
05091 
05092     // add to the cache and regenerate if we didn't find it
05093     if (ogl_cachedid == GLCACHE_FAIL) {
05094       ogl_cachedid = glGenLists(1);
05095       displaylistcache.encache(cmdList->serial, ogl_cachedid);
05096 
05097       // create the display list, and execute it.
05098       glNewList(ogl_cachedid, GL_COMPILE_AND_EXECUTE);
05099       ogl_cachecreated = 1; // a new display list was created
05100     }
05101   }
05102 
05103   // XXX Draw OpenGL geometry only when caching is disabled or when
05104   //     we have new geometry to cache
05105   if ((!ogl_cacheenabled) || ogl_cacheskip || (ogl_cacheenabled && ogl_cachecreated)) {
05106 #endif
05107 
05108 
05109   // scan through the list, getting each command and executing it, until
05110   // the end of commands token is found
05111   int colorIndex = 0;
05112   VMDDisplayList::VMDLinkIter cmditer;
05113   cmdList->first(&cmditer);
05114   while((tok = cmdList->next(&cmditer, cmdptr)) != DLASTCOMMAND) {
05115     switch (tok) {
05116       case DCOLORINDEX:
05117         colorIndex = (((DispCmdColorIndex *)cmdptr)->color);
05118         break;
05119 
05120       case DCYLINDER: // plot a cylinder
05121         {
05122         add_material_cmdlist(cmdList);
05123 
05124         // XXX these should be getting aggregated in a batch
05125 
05126         float points[6], radii[1], colors[3];
05127         memcpy(points,           (float *)cmdptr, 3L*sizeof(float));
05128         memcpy(&points[3], ((float *)cmdptr) + 3, 3L*sizeof(float));
05129         radii[0] = ((float *)cmdptr)[6];
05130         int filled = ((int) ((float *) cmdptr)[8]); 
05131         memcpy(colors, &colorData[colorIndex*3L], 3L*sizeof(float));
05132 
05133         float *mat =  &transMat.top().mat[0];
05134         float scaleFactor =
05135           (sqrtf(mat[0]*mat[0] + mat[4]*mat[4] + mat[ 8]*mat[ 8]) +
05136            sqrtf(mat[1]*mat[1] + mat[5]*mat[5] + mat[ 9]*mat[ 9]) +
05137            sqrtf(mat[2]*mat[2] + mat[6]*mat[6] + mat[10]*mat[10])) / 3.0f;
05138 
05139         // Submit all geometry in one buffer
05140         cylinder_array_color(&transMat.top(), scaleFactor,
05141                              1, points, radii, colors,
05142                              cmdList->materialtag);
05143 
05144         // XXX no filled cylinder caps yet
05145 
05146         }
05147         break;
05148 
05149       case DCYLINDERARRAY:
05150         {
05151         add_material_cmdlist(cmdList);
05152 
05153         DispCmdCylinderArray *ca = (DispCmdCylinderArray *)cmdptr;
05154         float *points, *radii, *colors;
05155         ca->getpointers(points, radii, colors);
05156 
05157         float *mat =  &transMat.top().mat[0];
05158         float scaleFactor =
05159           (sqrtf(mat[0]*mat[0] + mat[4]*mat[4] + mat[ 8]*mat[ 8]) +
05160            sqrtf(mat[1]*mat[1] + mat[5]*mat[5] + mat[ 9]*mat[ 9]) +
05161            sqrtf(mat[2]*mat[2] + mat[6]*mat[6] + mat[10]*mat[10])) / 3.0f;
05162 
05163         // Submit all geometry in one buffer
05164         cylinder_array_color(&transMat.top(), scaleFactor,
05165                              ca->numcylinders, points, radii, colors,
05166                              cmdList->materialtag);
05167         }
05168         break;
05169 
05170       case DSPHERE:
05171         {
05172         add_material_cmdlist(cmdList);
05173 
05174         // XXX these should be getting aggregated in a batch
05175 
05176         float centers[3], radii[1], color[3];
05177         memcpy(centers, (float *)cmdptr, 3L*sizeof(float));
05178         radii[0] = ((float *)cmdptr)[3];
05179 
05180         float *mat =  &transMat.top().mat[0];
05181         float scaleFactor =
05182           (sqrtf(mat[0]*mat[0] + mat[4]*mat[4] + mat[ 8]*mat[ 8]) +
05183            sqrtf(mat[1]*mat[1] + mat[5]*mat[5] + mat[ 9]*mat[ 9]) +
05184            sqrtf(mat[2]*mat[2] + mat[6]*mat[6] + mat[10]*mat[10])) / 3.0f;
05185 
05186         // Submit all geometry in one buffer
05187         sphere_array_color(transMat.top(), scaleFactor,
05188                            1, centers, radii, &colorData[colorIndex*3L],
05189                            cmdList->materialtag);
05190         } 
05191         break;
05192 
05193       case DSPHEREARRAY:
05194         {
05195         add_material_cmdlist(cmdList);
05196 
05197         DispCmdSphereArray *sa = (DispCmdSphereArray *)cmdptr;
05198         float *centers, *radii, *colors;
05199         sa->getpointers(centers, radii, colors);
05200 
05201         float *mat =  &transMat.top().mat[0];
05202         float scaleFactor =
05203           (sqrtf(mat[0]*mat[0] + mat[4]*mat[4] + mat[ 8]*mat[ 8]) +
05204            sqrtf(mat[1]*mat[1] + mat[5]*mat[5] + mat[ 9]*mat[ 9]) +
05205            sqrtf(mat[2]*mat[2] + mat[6]*mat[6] + mat[10]*mat[10])) / 3.0f;
05206 
05207         // Submit all geometry in one buffer
05208         sphere_array_color(transMat.top(), scaleFactor,
05209                            sa->numspheres, centers, radii, colors,
05210                            cmdList->materialtag);
05211         }
05212         break;
05213 
05214       case DTRIMESH_C3F_N3F_V3F: // draw a triangle mesh
05215         {
05216         add_material_cmdlist(cmdList);
05217 
05218         DispCmdTriMesh *cmd = (DispCmdTriMesh *) cmdptr;
05219         float *c=NULL, *n=NULL, *v=NULL;
05220 
05221         if (cmd->pervertexcolors) {
05222           cmd->getpointers(c, n, v);
05223 #if 1
05224           printf("Dropped trimesh_c3f_n3f_v3f()\n");
05225 #else
05226           // XXX unimplemented
05227           trimesh_c3f_n3f_v3f(transMat.top(), c, n, v, cmd->numfacets, 
05228                               cmdList->materialtag);
05229 #endif
05230         } else if (cmd->pervertexnormals) {
05231           cmd->getpointers(n, v);
05232           trimesh_n3f_v3f(transMat.top(), &colorData[colorIndex * 3],
05233                           n, v, cmd->numfacets, cmdList->materialtag);
05234         } else {
05235           cmd->getpointers(n, v);
05236           trimesh_v3f(transMat.top(), &colorData[colorIndex * 3],
05237                       v, cmd->numfacets, cmdList->materialtag);
05238         }
05239         }
05240         break;
05241 
05242       case DTRIMESH_C4F_N3F_V3F:
05243         {
05244         add_material_cmdlist(cmdList);
05245 
05246         // draw a triangle mesh
05247         DispCmdTriMesh *cmd = (DispCmdTriMesh *) cmdptr;
05248         int ind = cmd->numfacets * 3;
05249         float *cnv;
05250         int *f;
05251         cmd->getpointers(cnv, f);
05252         trimesh_c4n3v3(transMat.top(), cmd->numverts, cnv, cmd->numfacets, f,
05253                        cmdList->materialtag);
05254         }
05255         break;
05256 
05257       case DTRIMESH_C4U_N3B_V3F: // draw a triangle mesh
05258         {
05259         add_material_cmdlist(cmdList);
05260 
05261         DispCmdTriMesh *cmd = (DispCmdTriMesh *) cmdptr;
05262         unsigned char *c=NULL;
05263         signed char *n=NULL;
05264         float *v=NULL;
05265 
05266         if (cmd->pervertexcolors) {
05267           cmd->getpointers(c, n, v);
05268           trimesh_c4u_n3b_v3f(transMat.top(), c, n, v, cmd->numfacets, 
05269                               cmdList->materialtag);
05270         } else {
05271           cmd->getpointers(n, v);
05272           trimesh_n3b_v3f(transMat.top(), &colorData[colorIndex * 3],
05273                           n, v, cmd->numfacets, cmdList->materialtag);
05274         }
05275         }
05276         break;
05277 
05278       case DTRISTRIP:     // draw a triangle strip
05279         {
05280         add_material_cmdlist(cmdList);
05281 
05282         DispCmdTriStrips *cmd = (DispCmdTriStrips *) cmdptr;
05283         float *cnv=NULL;
05284         int *f=NULL;
05285         int *vertsperstrip;
05286         cmd->getpointers(cnv, f, vertsperstrip);
05287         tristrip(transMat.top(), cmd->numverts, cnv, cmd->numstrips, 
05288                  vertsperstrip, f, cmdList->materialtag);
05289         }
05290         break;
05291 
05292 
05293 #if 0
05294       default:
05295         // msgErr << "OpenGLRenderer: Unknown drawing token " << tok
05296         //        << " encountered ... Skipping this command." << sendmsg;
05297         break;
05298 #endif
05299     }
05300   }
05301 }
05302 
05303 
05305 void OptiXRenderer::scene_aggregation_complete() {
05306   update_rendering_state(0);
05307   render_compile_and_validate();
05308 }
05309 
05310 
05311 // launch rendering pass(es)
05312 void OptiXRenderer::render_current_scene() {
05313   if (lasterror == RT_SUCCESS) {
05314     // clear the accumulation buffer
05315     RTERR( rtContextLaunch2D(ctx, RT_RAY_GEN_CLEAR_ACCUMULATION_BUFFER, width, height) );
05316 
05317     // Render to the accumulation buffer for the required number of passes
05318     if (getenv("VMDOPTIXNORENDER") == NULL) {
05319       int accum_sample;
05320       for (accum_sample=0; accum_sample<ext_aa_loops; accum_sample++) {
05321         // The accumulation subframe count must be updated to ensure that
05322         // the RNGs for AA and AO get correctly re-seeded
05323         RTERR( rtVariableSet1ui(accum_count_v, accum_sample) );
05324         RTERR( rtContextLaunch2D(ctx, RT_RAY_GEN_ACCUMULATE, width, height) );
05325       }
05326     }
05327 
05328     // copy the accumulation buffer image data to the framebuffer and perform
05329     // type conversion and normaliztion on the image data...
05330     RTERR( rtContextLaunch2D(ctx, RT_RAY_GEN_COPY_FINISH, width, height) );
05331   }
05332 } 
05333 
05334 #endif
05335 
05336 
05337 void OptiXRenderer::destroy_context() {
05338   if (!context_created)
05339     return;
05340 
05341 #ifdef VMDOPTIX_PROGRESSIVEAPI
05342   // ensure that there's no way we could be leaving the VCA running
05343   rtContextStopProgressive(ctx);
05344 #endif
05345 
05346   framebuffer_destroy();
05347 
05348   if ((lasterror = rtContextDestroy(ctx)) != RT_SUCCESS) {
05349     msgErr << "OptiXRenderer) An error occured while destroying the OptiX context" << sendmsg;
05350   }
05351 }
05352 
05353 
05354 void OptiXRenderer::add_material(int matindex,
05355                                  float ambient, float diffuse, float specular,
05356                                  float shininess, float reflectivity,
05357                                  float opacity, 
05358                                  float outline, float outlinewidth,
05359                                  int transmode) {
05360   int oldmatcount = materialcache.num();
05361   if (oldmatcount <= matindex) {
05362     ort_material m;
05363     memset(&m, 0, sizeof(m));
05364 
05365     // XXX do something noticable so we see that we got a bad entry...
05366     m.ambient = 0.5f;
05367     m.diffuse = 0.7f;
05368     m.specular = 0.0f;
05369     m.shininess = 10.0f;
05370     m.reflectivity = 0.0f;
05371     m.opacity = 1.0f;
05372     m.transmode = 0;
05373 
05374     materialcache.appendN(m, matindex - oldmatcount + 1);
05375   }
05376  
05377   if (materialcache[matindex].isvalid) {
05378     return;
05379   } else {
05380     if (verbose == RT_VERB_DEBUG) printf("OptiXRenderer) Adding material[%d]\n", matindex);
05381 
05382     materialcache[matindex].ambient      = ambient;
05383     materialcache[matindex].diffuse      = diffuse; 
05384     materialcache[matindex].specular     = specular;
05385     materialcache[matindex].shininess    = shininess;
05386     materialcache[matindex].reflectivity = reflectivity;
05387     materialcache[matindex].opacity      = opacity;
05388     materialcache[matindex].outline      = outline;
05389     materialcache[matindex].outlinewidth = outlinewidth;
05390     materialcache[matindex].transmode    = transmode;
05391     materialcache[matindex].isvalid      = 1;
05392   }
05393 }
05394 
05395 
05396 void OptiXRenderer::init_materials() {
05397   if (verbose == RT_VERB_DEBUG) printf("OptiXRenderer) init_materials()\n");
05398 
05399   // pre-register all of the hit programs to be shared by all materials
05400   RTERR( rtProgramCreateFromPTXFile(ctx, shaderpath, "closest_hit_radiance_general", &closest_hit_pgm_general) );
05401 #if defined(ORT_USERTXAPIS)
05402   // OptiX RTX triangle API
05403   RTERR( rtProgramCreateFromPTXFile(ctx, shaderpath, "closest_hit_radiance_general_hwtri", &closest_hit_pgm_general_hwtri) );
05404 #endif
05405 
05406 #if defined(ORT_USE_TEMPLATE_SHADERS)
05407   // build up the list of closest hit programs from all combinations
05408   // of shader parameters
05409   int i;
05410   for (i=0; i<ORTMTABSZ; i++) {
05411     char ch_program_name[256];
05412     snprintf(ch_program_name, sizeof(ch_program_name),
05413              "closest_hit_radiance_"
05414              "CLIP_VIEW_%s_"
05415              "HEADLIGHT_%s_"
05416              "FOG_%s_"
05417              "SHADOWS_%s_"
05418              "AO_%s_"
05419              "OUTLINE_%s_"
05420              "REFL_%s_"
05421              "TRANS_%s",
05422 #if defined(VMDOPTIX_VCA_TABSZHACK)
05423              onoffstr(1),
05424              onoffstr(1),
05425 #else
05426              onoffstr(i & 128),
05427              onoffstr(i &  64),
05428 #endif
05429              onoffstr(i &  32),
05430              onoffstr(i &  16),
05431              onoffstr(i &   8),
05432              onoffstr(i &   4),
05433              onoffstr(i &   2),
05434              onoffstr(i &   1));
05435 
05436     RTERR( rtProgramCreateFromPTXFile(ctx, shaderpath, ch_program_name, &closest_hit_pgm_special[i] ) );
05437 
05438 #if defined(ORT_USERTXAPIS)
05439   #error OptiX RTX triangle API not implemented for template shader expansion
05440 #endif
05441 
05442   } 
05443 #endif
05444 
05445   RTERR( rtProgramCreateFromPTXFile(ctx, shaderpath, "any_hit_opaque", &any_hit_pgm_opaque) );
05446   RTERR( rtProgramCreateFromPTXFile(ctx, shaderpath, "any_hit_transmission", &any_hit_pgm_transmission) );
05447   RTERR( rtProgramCreateFromPTXFile(ctx, shaderpath, "any_hit_clip_sphere", &any_hit_pgm_clip_sphere) );
05448 
05449   RTERR( rtMaterialCreate(ctx, &material_general) );
05450   RTERR( rtMaterialSetClosestHitProgram(material_general, RT_RAY_TYPE_RADIANCE, closest_hit_pgm_general) );
05451   RTERR( rtMaterialSetAnyHitProgram(material_general, RT_RAY_TYPE_SHADOW, any_hit_pgm_clip_sphere) );
05452 
05453 
05454 #if defined(ORT_USERTXAPIS)
05455   RTERR( rtMaterialCreate(ctx, &material_general_hwtri) );
05456   RTERR( rtMaterialSetClosestHitProgram(material_general_hwtri, RT_RAY_TYPE_RADIANCE, closest_hit_pgm_general_hwtri) );
05457   RTERR( rtMaterialSetAnyHitProgram(material_general_hwtri, RT_RAY_TYPE_SHADOW, any_hit_pgm_clip_sphere) );
05458 #endif
05459 
05460 
05461 #if defined(ORT_USE_TEMPLATE_SHADERS)
05462   // build up the list of materials from all combinations of shader parameters
05463   for (i=0; i<ORTMTABSZ; i++) {
05464     RTERR( rtMaterialCreate(ctx, &material_special[i]) );
05465     RTERR( rtMaterialSetClosestHitProgram(material_special[i], RT_RAY_TYPE_RADIANCE, closest_hit_pgm_special[i]) );
05466 
05467     // select correct any hit program depending on opacity
05468     if (clipview_mode == RT_CLIP_SPHERE) {
05469       RTERR( rtMaterialSetAnyHitProgram(material_special[i], RT_RAY_TYPE_SHADOW, any_hit_pgm_clip_sphere) );
05470     } else {
05471       if (i & 1) {
05472         RTERR( rtMaterialSetAnyHitProgram(material_special[i], RT_RAY_TYPE_SHADOW, any_hit_pgm_transmission) );
05473       } else {
05474         RTERR( rtMaterialSetAnyHitProgram(material_special[i], RT_RAY_TYPE_SHADOW, any_hit_pgm_opaque) );
05475       }
05476     }
05477 
05478 #if defined(ORT_USERTXAPIS)
05479   #error OptiX RTX triangle API not implemented for template shader expansion
05480 #endif
05481 
05482     // zero out the array of material usage counts for the scene
05483     material_special_counts[i] = 0;
05484   }
05485 #endif
05486 }
05487 
05488 
05489 void OptiXRenderer::set_material(RTgeometryinstance instance, int matindex, 
05490                                  const float *uniform_color, int hwtri) {
05491   if (!context_created)
05492     return;
05493 
05494 //if (verbose == RT_VERB_DEBUG) printf("OptiXRenderer) setting material\n");
05495   RTvariable ka, kd, ks, phongexp, krefl;
05496   RTvariable opacity, outline, outlinewidth, transmode, uniform_col;
05497   RTmaterial material = material_general; 
05498 
05499 #if defined(ORT_USERTXAPIS)
05500   // OptiX RTX hardware-triangle APIs require special material handling
05501   if (hwtri) {
05502     material = material_general_hwtri;
05503   }
05504 #endif
05505 
05506 #if defined(ORT_USE_TEMPLATE_SHADERS)
05507   if (getenv("VMDOPTIXFORCEGENERALSHADER") == NULL) {
05508     unsigned int specialized_material_index = 
05509       ((clipview_mode != RT_CLIP_NONE)             << 7) |   // VR clip pln/sph
05510       ((headlight_mode != RT_HEADLIGHT_OFF)        << 6) |   // VR headlight
05511       ((fog_mode != RT_FOG_NONE)                   << 5) |   // fog
05512       ((shadows_enabled != RT_SHADOWS_OFF)         << 4) |   // shadows
05513       ((ao_samples != 0)                           << 3) |   // AO
05514       ((materialcache[matindex].outline != 0)      << 2) |   // outline
05515       ((materialcache[matindex].reflectivity != 0) << 1) |   // reflection
05516       ((materialcache[matindex].opacity != 1)          );    // transmission
05517 
05518 #if defined(VMDOPTIX_VCA_TABSZHACK)
05519     // XXX hack to mask down the material index down to the range 
05520     //     that works without creating trouble for the VCA
05521     if (specialized_material_index >= ORTMTABSZ) { 
05522       specialized_material_index &= (ORTMTABSZ - 1);
05523     }
05524 #endif
05525 
05526     material = material_special[specialized_material_index];
05527 
05528     // increment material usage counter
05529     material_special_counts[specialized_material_index]++;
05530   }
05531 #endif
05532 
05533   RTERR( rtGeometryInstanceSetMaterialCount(instance, 1) );
05534   RTERR( rtGeometryInstanceSetMaterial(instance, 0, material) );
05535 
05536   if (uniform_color != NULL) {
05537     RTERR( rtGeometryInstanceDeclareVariable(instance, "uniform_color", &uniform_col) );
05538     RTERR( rtVariableSet3fv(uniform_col, uniform_color) );
05539   }
05540 
05541   RTERR( rtGeometryInstanceDeclareVariable(instance, "Ka", &ka) );
05542   RTERR( rtGeometryInstanceDeclareVariable(instance, "Kd", &kd) );
05543   RTERR( rtGeometryInstanceDeclareVariable(instance, "Ks", &ks) );
05544   RTERR( rtGeometryInstanceDeclareVariable(instance, "phong_exp", &phongexp) );
05545   RTERR( rtGeometryInstanceDeclareVariable(instance, "Krefl", &krefl) );
05546   RTERR( rtGeometryInstanceDeclareVariable(instance, "opacity", &opacity) );
05547   RTERR( rtGeometryInstanceDeclareVariable(instance, "outline", &outline) );
05548   RTERR( rtGeometryInstanceDeclareVariable(instance, "outlinewidth", &outlinewidth) );
05549   RTERR( rtGeometryInstanceDeclareVariable(instance, "transmode", &transmode) );
05550 
05551   RTERR( rtVariableSet1f(ka, materialcache[matindex].ambient) );
05552   RTERR( rtVariableSet1f(kd, materialcache[matindex].diffuse) );
05553   RTERR( rtVariableSet1f(ks, materialcache[matindex].specular) );
05554   RTERR( rtVariableSet1f(phongexp, materialcache[matindex].shininess) );
05555   RTERR( rtVariableSet1f(krefl, materialcache[matindex].reflectivity) );
05556   RTERR( rtVariableSet1f(opacity, materialcache[matindex].opacity) );
05557   RTERR( rtVariableSet1f(outline, materialcache[matindex].outline) );
05558   RTERR( rtVariableSet1f(outlinewidth, materialcache[matindex].outlinewidth) );
05559   RTERR( rtVariableSet1i(transmode, materialcache[matindex].transmode) );
05560 }
05561 
05562 
05563 void OptiXRenderer::add_directional_light(const float *dir, const float *color) {
05564   ort_directional_light l;
05565   vec_copy(l.dir, dir);
05566   vec_copy(l.color, color);
05567 
05568   directional_lights.append(l);
05569 }
05570 
05571 
05572 void OptiXRenderer::add_positional_light(const float *pos, const float *color) {
05573   ort_positional_light l;
05574   vec_copy(l.pos, pos);
05575   vec_copy(l.color, color);
05576 
05577   positional_lights.append(l);
05578 }
05579 
05580 
05583 float OptiXRenderer::calc_matrix_scale_factor(const float *mat) {
05584   float scaleFactor =
05585     (sqrtf(mat[0]*mat[0] + mat[4]*mat[4] + mat[ 8]*mat[ 8]) +
05586      sqrtf(mat[1]*mat[1] + mat[5]*mat[5] + mat[ 9]*mat[ 9]) +
05587      sqrtf(mat[2]*mat[2] + mat[6]*mat[6] + mat[10]*mat[10])) / 3.0f;
05588 
05589   return scaleFactor;
05590 }
05591 
05592 
05593 void OptiXRenderer::cylinder_array(Matrix4 *wtrans, float radius,
05594                                    const float *uniform_color,
05595                                    int cylnum, const float *points, 
05596                                    int matindex) {
05597   if (!context_created) return;
05598   if (verbose == RT_VERB_DEBUG) printf("OptiXRenderer) creating cylinder array: %d...\n", cylnum);
05599   cylinder_array_cnt += cylnum;
05600 
05601   int i, ind;
05602   RTbuffer buf;
05603   RTgeometry geom;
05604   RTgeometryinstance instance;
05605   vmd_cylinder *cyldata;
05606 
05607   // create and fill the OptiX cylinder array memory buffer
05608   rtBufferCreate(ctx, RT_BUFFER_INPUT, &buf);
05609   rtBufferSetFormat(buf, RT_FORMAT_USER);
05610   rtBufferSetElementSize(buf, sizeof(vmd_cylinder));
05611   rtBufferSetSize1D(buf, cylnum);
05612   // rtBufferValidate(buf);
05613   rtBufferMap(buf, (void **) &cyldata); // map buffer for writing by host
05614 
05615   if (wtrans == NULL) {
05616     for (i=0,ind=0; i<cylnum; i++,ind+=6) {
05617       // transform to eye coordinates
05618       vec_copy((float*) &cyldata[i].start, &points[ind]);
05619       cyldata[i].radius = radius;
05620       vec_sub((float*) &cyldata[i].axis, &points[ind+3], &points[ind]);
05621     }
05622   } else {
05623     for (i=0,ind=0; i<cylnum; i++,ind+=6) {
05624       // transform to eye coordinates
05625       wtrans->multpoint3d(&points[ind], (float*) &cyldata[i].start);
05626       cyldata[i].radius = radius;
05627       float ctmp[3];
05628       wtrans->multpoint3d(&points[ind+3], ctmp);
05629       vec_sub((float*) &cyldata[i].axis, ctmp, &points[ind]);
05630     }
05631   }
05632   rtBufferUnmap(buf); // cylinder array is complete, unmap buffer
05633 
05634   RTERR( rtGeometryCreate(ctx, &geom) );
05635   RTERR( rtGeometrySetPrimitiveCount(geom, cylnum) );
05636   RTERR( rtGeometrySetBoundingBoxProgram(geom, cylinder_array_bbox_pgm) );
05637   RTERR( rtGeometrySetIntersectionProgram(geom, cylinder_array_isct_pgm) );
05638 
05639   // this cyl buffer is associated only with this particular geometry node
05640   RTvariable buf_v;
05641   RTERR( rtGeometryDeclareVariable(geom, "cylinder_buffer", &buf_v) );
05642   RTERR( rtVariableSetObject(buf_v, buf) );
05643 
05644   // create a geometry instance node and bind materials to this geometry
05645   RTERR( rtGeometryInstanceCreate(ctx, &instance) );
05646   RTERR( rtGeometryInstanceSetGeometry(instance, geom) );
05647 
05648   set_material(instance, matindex, uniform_color);
05649 
05650   append_objects(buf, geom, instance);
05651 }
05652 
05653 
05654 void OptiXRenderer::cylinder_array_color(Matrix4 *wtrans, float rscale,
05655                                          int cylnum, const float *points, 
05656                                          const float *radii, 
05657                                          const float *colors, int matindex) {
05658   if (!context_created) return;
05659   if (verbose == RT_VERB_DEBUG) printf("OptiXRenderer) creating cylinder color array: %d...\n", cylnum);
05660   cylinder_array_color_cnt += cylnum;
05661 
05662   int i, ind;
05663   RTbuffer buf;
05664   RTgeometry geom;
05665   RTgeometryinstance instance;
05666   vmd_cylinder_color *cyldata;
05667 
05668   // create and fill the OptiX cylinder array memory buffer
05669   rtBufferCreate(ctx, RT_BUFFER_INPUT, &buf);
05670   rtBufferSetFormat(buf, RT_FORMAT_USER);
05671   rtBufferSetElementSize(buf, sizeof(vmd_cylinder_color));
05672   rtBufferSetSize1D(buf, cylnum);
05673   // rtBufferValidate(buf);
05674   rtBufferMap(buf, (void **) &cyldata); // map buffer for writing by host
05675 
05676   if (wtrans == NULL) {
05677     // already transformed to eye coordinates
05678     if (radii == NULL) {
05679       for (i=0,ind=0; i<cylnum; i++,ind+=6) {
05680         vec_copy((float*) &cyldata[i].start, &points[ind]);
05681         cyldata[i].radius = rscale;
05682         vec_sub((float*) &cyldata[i].axis, &points[ind+3], &points[ind]);
05683         vec_copy((float*) &cyldata[i].color, &colors[i*3]);
05684       }
05685     } else {
05686       for (i=0,ind=0; i<cylnum; i++,ind+=6) {
05687         vec_copy((float*) &cyldata[i].start, &points[ind]);
05688         cyldata[i].radius = rscale * radii[i];
05689         vec_sub((float*) &cyldata[i].axis, &points[ind+3], &points[ind]);
05690         vec_copy((float*) &cyldata[i].color, &colors[i*3]);
05691       }
05692     }
05693   } else {
05694     // transform to eye coordinates
05695     if (radii == NULL) {
05696       for (i=0,ind=0; i<cylnum; i++,ind+=6) {
05697         wtrans->multpoint3d(&points[ind], (float*) &cyldata[i].start);
05698         cyldata[i].radius = rscale;
05699         float ctmp[3];
05700         wtrans->multpoint3d(&points[ind+3], ctmp);
05701         vec_sub((float*) &cyldata[i].axis, ctmp, (float*) &cyldata[i].start);
05702         vec_copy((float*) &cyldata[i].color, &colors[i*3]);
05703       }
05704     } else {
05705       for (i=0,ind=0; i<cylnum; i++,ind+=6) {
05706         wtrans->multpoint3d(&points[ind], (float*) &cyldata[i].start);
05707         cyldata[i].radius = rscale * radii[i];
05708         float ctmp[3];
05709         wtrans->multpoint3d(&points[ind+3], ctmp);
05710         vec_sub((float*) &cyldata[i].axis, ctmp, (float*) &cyldata[i].start);
05711         vec_copy((float*) &cyldata[i].color, &colors[i*3]);
05712       }
05713     }
05714   }
05715   rtBufferUnmap(buf); // cylinder array is complete, unmap buffer
05716 
05717   RTERR( rtGeometryCreate(ctx, &geom) );
05718   RTERR( rtGeometrySetPrimitiveCount(geom, cylnum) );
05719   RTERR( rtGeometrySetBoundingBoxProgram(geom, cylinder_array_color_bbox_pgm) );
05720   RTERR( rtGeometrySetIntersectionProgram(geom, cylinder_array_color_isct_pgm) );
05721 
05722   // this cyl buffer is associated only with this particular geometry node
05723   RTvariable buf_v;
05724   RTERR( rtGeometryDeclareVariable(geom, "cylinder_color_buffer", &buf_v) );
05725   RTERR( rtVariableSetObject(buf_v, buf) );
05726 
05727   // create a geometry instance node and bind materials to this geometry
05728   RTERR( rtGeometryInstanceCreate(ctx, &instance) );
05729   RTERR( rtGeometryInstanceSetGeometry(instance, geom) );
05730 
05731   set_material(instance, matindex, NULL);
05732 
05733   append_objects(buf, geom, instance);
05734 }
05735 
05736 
05737 void OptiXRenderer::ring_array_color(Matrix4 & wtrans, float rscale,
05738                                      int rnum, const float *centers,
05739                                      const float *norms, const float *radii, 
05740                                      const float *colors, int matindex) {
05741   if (!context_created) return;
05742   if (verbose == RT_VERB_DEBUG) printf("OptiXRenderer) creating ring array color: %d...\n", rnum);
05743   ring_array_color_cnt += rnum;
05744 
05745   int i, ind;
05746   RTbuffer buf;
05747   RTgeometry geom;
05748   RTgeometryinstance instance;
05749   vmd_ring_color *rdata;
05750 
05751   // create and fill the OptiX ring array memory buffer
05752   rtBufferCreate(ctx, RT_BUFFER_INPUT, &buf);
05753   rtBufferSetFormat(buf, RT_FORMAT_USER);
05754   rtBufferSetElementSize(buf, sizeof(vmd_ring_color));
05755   rtBufferSetSize1D(buf, rnum);
05756   // rtBufferValidate(buf);
05757   rtBufferMap(buf, (void **) &rdata); // map buffer for writing by host
05758 
05759   for (i=0,ind=0; i<rnum; i++,ind+=3) {
05760     // transform to eye coordinates
05761     wtrans.multpoint3d(&centers[ind], (float*) &rdata[i].center);
05762     wtrans.multnorm3d(&norms[ind], (float*) &rdata[i].norm);
05763     vec_normalize((float*) &rdata[i].norm);
05764     rdata[i].inrad  = rscale * radii[i*2];
05765     rdata[i].outrad = rscale * radii[i*2+1];
05766     vec_copy((float*) &rdata[i].color, &colors[ind]);
05767     rdata[i].pad = 0.0f; // please valgrind  
05768   }
05769   rtBufferUnmap(buf); // ring array is complete, unmap buffer
05770 
05771   RTERR( rtGeometryCreate(ctx, &geom) );
05772   RTERR( rtGeometrySetPrimitiveCount(geom, rnum) );
05773   RTERR( rtGeometrySetBoundingBoxProgram(geom, ring_array_color_bbox_pgm) );
05774   RTERR( rtGeometrySetIntersectionProgram(geom, ring_array_color_isct_pgm) );
05775 
05776   // this ring buffer is associated only with this particular geometry node
05777   RTvariable buf_v;
05778   RTERR( rtGeometryDeclareVariable(geom, "ring_color_buffer", &buf_v) );
05779   RTERR( rtVariableSetObject(buf_v, buf) );
05780 
05781   // create a geometry instance node and bind materials to this geometry
05782   RTERR( rtGeometryInstanceCreate(ctx, &instance) );
05783   RTERR( rtGeometryInstanceSetGeometry(instance, geom) );
05784 
05785   set_material(instance, matindex, NULL);
05786 
05787   append_objects(buf, geom, instance);
05788 }
05789 
05790 
05791 void OptiXRenderer::sphere_array(Matrix4 *wtrans, float rscale,
05792                                  const float *uniform_color,
05793                                  int spnum, const float *centers,
05794                                  const float *radii,
05795                                  int matindex) {
05796   if (!context_created) return;
05797   if (verbose == RT_VERB_DEBUG) printf("OptiXRenderer) creating sphere array: %d...\n", spnum);
05798   sphere_array_cnt += spnum;
05799 
05800   int i, ind;
05801   RTbuffer buf;
05802   RTgeometry geom;
05803   RTgeometryinstance instance;
05804   vmd_sphere *spdata;
05805 
05806   // create and fill the OptiX sphere array memory buffer
05807   rtBufferCreate(ctx, RT_BUFFER_INPUT, &buf);
05808   rtBufferSetFormat(buf, RT_FORMAT_USER);
05809   rtBufferSetElementSize(buf, sizeof(vmd_sphere));
05810   rtBufferSetSize1D(buf, spnum);
05811   // rtBufferValidate(buf);
05812   rtBufferMap(buf, (void **) &spdata); // map buffer for writing by host
05813 
05814   if (wtrans == NULL) {
05815     if (radii == NULL) {
05816       for (i=0,ind=0; i<spnum; i++,ind+=3) {
05817         // transform to eye coordinates
05818         vec_copy((float*) &spdata[i].center, &centers[ind]);
05819         spdata[i].radius = rscale; // use "rscale" as radius...
05820       }
05821     } else {
05822       for (i=0,ind=0; i<spnum; i++,ind+=3) {
05823         // transform to eye coordinates
05824         vec_copy((float*) &spdata[i].center, &centers[ind]);
05825         spdata[i].radius = rscale * radii[i];
05826       }
05827     }
05828   } else {
05829     if (radii == NULL) {
05830       for (i=0,ind=0; i<spnum; i++,ind+=3) {
05831         // transform to eye coordinates
05832         wtrans->multpoint3d(&centers[ind], (float*) &spdata[i].center);
05833         spdata[i].radius = rscale; // use "rscale" as radius...
05834       }
05835     } else {
05836       for (i=0,ind=0; i<spnum; i++,ind+=3) {
05837         // transform to eye coordinates
05838         wtrans->multpoint3d(&centers[ind], (float*) &spdata[i].center);
05839         spdata[i].radius = rscale * radii[i];
05840       }
05841     }
05842   }
05843   rtBufferUnmap(buf); // sphere array is complete, unmap buffer
05844 
05845   RTERR( rtGeometryCreate(ctx, &geom) );
05846   RTERR( rtGeometrySetPrimitiveCount(geom, spnum) );
05847   RTERR( rtGeometrySetBoundingBoxProgram(geom, sphere_array_bbox_pgm) );
05848   RTERR( rtGeometrySetIntersectionProgram(geom, sphere_array_isct_pgm) );
05849 
05850   // this sphere buffer is associated only with this particular geometry node
05851   RTvariable buf_v;
05852   RTERR( rtGeometryDeclareVariable(geom, "sphere_buffer", &buf_v) );
05853   RTERR( rtVariableSetObject(buf_v, buf) );
05854 
05855   // create a geometry instance node and bind materials to this geometry
05856   RTERR( rtGeometryInstanceCreate(ctx, &instance) );
05857   RTERR( rtGeometryInstanceSetGeometry(instance, geom) );
05858 
05859   set_material(instance, matindex, uniform_color);
05860 
05861   append_objects(buf, geom, instance);
05862 }
05863 
05864 
05865 void OptiXRenderer::sphere_array_color(Matrix4 & wtrans, float rscale,
05866                                        int spnum, const float *centers,
05867                                        const float *radii, const float *colors,
05868                                        int matindex) {
05869   if (!context_created) return;
05870   if (verbose == RT_VERB_DEBUG) printf("OptiXRenderer) creating sphere array color: %d...\n", spnum);
05871   sphere_array_color_cnt += spnum;
05872 
05873   int i, ind;
05874   RTbuffer buf;
05875   RTgeometry geom;
05876   RTgeometryinstance instance;
05877   vmd_sphere_color *spdata;
05878 
05879   // create and fill the OptiX sphere array memory buffer
05880   rtBufferCreate(ctx, RT_BUFFER_INPUT, &buf);
05881   rtBufferSetFormat(buf, RT_FORMAT_USER);
05882   rtBufferSetElementSize(buf, sizeof(vmd_sphere_color));
05883   rtBufferSetSize1D(buf, spnum);
05884   // rtBufferValidate(buf);
05885   rtBufferMap(buf, (void **) &spdata); // map buffer for writing by host
05886 
05887   for (i=0,ind=0; i<spnum; i++,ind+=3) {
05888     // transform to eye coordinates
05889     wtrans.multpoint3d(&centers[ind], (float*) &spdata[i].center);
05890     spdata[i].radius = rscale * radii[i];
05891     vec_copy((float*) &spdata[i].color, &colors[ind]);
05892     spdata[i].pad = 0.0f; // please valgrind
05893   }
05894   rtBufferUnmap(buf); // sphere array is complete, unmap buffer
05895 
05896   RTERR( rtGeometryCreate(ctx, &geom) );
05897   RTERR( rtGeometrySetPrimitiveCount(geom, spnum) );
05898   RTERR( rtGeometrySetBoundingBoxProgram(geom, sphere_array_color_bbox_pgm) );
05899   RTERR( rtGeometrySetIntersectionProgram(geom, sphere_array_color_isct_pgm) );
05900 
05901   // this sphere buffer is associated only with this particular geometry node
05902   RTvariable buf_v;
05903   RTERR( rtGeometryDeclareVariable(geom, "sphere_color_buffer", &buf_v) );
05904   RTERR( rtVariableSetObject(buf_v, buf) );
05905 
05906   // create a geometry instance node and bind materials to this geometry
05907   RTERR( rtGeometryInstanceCreate(ctx, &instance) );
05908   RTERR( rtGeometryInstanceSetGeometry(instance, geom) );
05909 
05910   set_material(instance, matindex, NULL);
05911 
05912   append_objects(buf, geom, instance);
05913 }
05914 
05915 
05916 #if defined(ORT_USERTXAPIS)
05917 void OptiXRenderer::tricolor_list_hwtri(Matrix4 & wtrans, int numtris, 
05918                                         const float *vnc, int matindex) {
05919   if (!context_created) return;
05920 //if (verbose == RT_VERB_DEBUG) printf("OptiXRenderer) creating tricolor list: %d...\n", numtris);
05921   tricolor_cnt += numtris;
05922 
05923   RTbuffer vbuf, nbuf, cbuf;
05924   RTgeometryinstance instance_hwtri;
05925   RTgeometrytriangles geom_hwtri;
05926   
05927   // Create and fill vertex/normal/color buffers
05928   float3 *vertices; 
05929   uint4 *normals;
05930   uchar4 *colors;
05931   hwtri_alloc_bufs_v3f_n4u4_c4u(ctx, numtris, vbuf, vertices, nbuf, normals, 
05932                                 cbuf, 1, colors, NULL);
05933 
05934   int i, ind, tcnt;
05935   for (i=0,ind=0,tcnt=0; i<numtris; i++,ind+=27) {
05936     int taddr = 3 * tcnt;
05937 
05938     // transform to eye coordinates
05939     wtrans.multpoint3d(&vnc[ind     ], (float*) &vertices[taddr + 0]);
05940     wtrans.multpoint3d(&vnc[ind +  3], (float*) &vertices[taddr + 1]);
05941     wtrans.multpoint3d(&vnc[ind +  6], (float*) &vertices[taddr + 2]);
05942 
05943     // Compute geometric normal, detect and cull degenerate triangles
05944     float3 Ng;
05945     if (hwtri_test_calc_Ngeom(&vertices[taddr], Ng)) {
05946       continue; // cull any triangle that fails degeneracy tests
05947     }
05948 
05949     float3 n0, n1, n2;
05950     wtrans.multnorm3d(&vnc[ind +  9], (float*) &n0);
05951     wtrans.multnorm3d(&vnc[ind + 12], (float*) &n1);
05952     wtrans.multnorm3d(&vnc[ind + 15], (float*) &n2);
05953 
05954     // Pack normals
05955     normals[tcnt].x = packNormal(Ng);
05956     normals[tcnt].y = packNormal(n0);
05957     normals[tcnt].z = packNormal(n1);
05958     normals[tcnt].w = packNormal(n2);
05959 
05960     // convert color format
05961     colors[taddr + 0].x = vnc[ind + 18] * 255.0f;
05962     colors[taddr + 0].y = vnc[ind + 19] * 255.0f;
05963     colors[taddr + 0].z = vnc[ind + 20] * 255.0f;
05964 
05965     colors[taddr + 1].x = vnc[ind + 21] * 255.0f;
05966     colors[taddr + 1].y = vnc[ind + 22] * 255.0f;
05967     colors[taddr + 1].z = vnc[ind + 23] * 255.0f;
05968 
05969     colors[taddr + 2].x = vnc[ind + 24] * 255.0f;
05970     colors[taddr + 2].y = vnc[ind + 25] * 255.0f;
05971     colors[taddr + 2].z = vnc[ind + 26] * 255.0f;
05972 
05973     tcnt++; // count non-culled triangles
05974   }
05975 
05976   rtBufferUnmap(vbuf);
05977   rtBufferUnmap(nbuf);
05978   rtBufferUnmap(cbuf);
05979 
05980   RTERR( rtGeometryTrianglesCreate(ctx, &geom_hwtri) );
05981   RTERR( rtGeometryTrianglesSetPrimitiveCount(geom_hwtri, tcnt) );
05982   RTERR( rtGeometryTrianglesSetVertices(geom_hwtri, tcnt * 3, vbuf, 
05983                                         0, sizeof(float3), RT_FORMAT_FLOAT3) );
05984 #if defined(VMDOPTIXRTXRELEASEBUFS)
05985   RTERR( rtGeometryTrianglesSetBuildFlags(geom_hwtri, RT_GEOMETRY_BUILD_FLAG_RELEASE_BUFFERS) );
05986 #else
05987   append_buffer(vbuf);
05988 #endif
05989 
05990   // create a geometry instance and bind materials to this geometry
05991   RTERR( rtGeometryInstanceCreate(ctx, &instance_hwtri) );
05992   RTERR( rtGeometryInstanceSetGeometryTriangles(instance_hwtri, geom_hwtri) );
05993 
05994   // Enable per-vertex normals, enable per-vertex colors
05995   hwtri_set_vertex_flags(ctx, instance_hwtri, nbuf, cbuf, 1, 1);
05996 
05997   // We have to pass the explicit hardware triangle parameter for this geometry
05998   set_material(instance_hwtri, matindex, NULL, 1);
05999 
06000   // The vertex buffer is released automatically after construction. 
06001   // We need to keep track of normal and color buffers for ourselves.
06002   append_objects(nbuf, cbuf, geom_hwtri, instance_hwtri);
06003 }
06004 #endif
06005 
06006 
06007 void OptiXRenderer::tricolor_list(Matrix4 & wtrans, int numtris, 
06008                                   const float *vnc, int matindex) {
06009   if (!context_created) return;
06010 //if (verbose == RT_VERB_DEBUG) printf("OptiXRenderer) creating tricolor list: %d...\n", numtris);
06011   tricolor_cnt += numtris;
06012 
06013   int i, ind;
06014   RTbuffer buf;
06015   RTgeometry geom;
06016   RTgeometryinstance instance;
06017   vmd_tricolor *trimesh;
06018 
06019   // create and fill the OptiX trimesh memory buffer
06020   rtBufferCreate(ctx, RT_BUFFER_INPUT, &buf);
06021   rtBufferSetFormat(buf, RT_FORMAT_USER);
06022   rtBufferSetElementSize(buf, sizeof(vmd_tricolor));
06023   rtBufferSetSize1D(buf, numtris);
06024   // rtBufferValidate(buf);
06025   rtBufferMap(buf, (void **) &trimesh); // map buffer for writing by host
06026 
06027   for (i=0,ind=0; i<numtris; i++,ind+=27) {
06028     // transform to eye coordinates
06029     wtrans.multpoint3d(&vnc[ind     ], (float*) &trimesh[i].v0);
06030     wtrans.multpoint3d(&vnc[ind +  3], (float*) &trimesh[i].v1);
06031     wtrans.multpoint3d(&vnc[ind +  6], (float*) &trimesh[i].v2);
06032 
06033     wtrans.multnorm3d(&vnc[ind +  9], (float*) &trimesh[i].n0);
06034     wtrans.multnorm3d(&vnc[ind + 12], (float*) &trimesh[i].n1);
06035     wtrans.multnorm3d(&vnc[ind + 15], (float*) &trimesh[i].n2);
06036 
06037     vec_copy((float*) &trimesh[i].c0, &vnc[ind + 18]);
06038     vec_copy((float*) &trimesh[i].c1, &vnc[ind + 21]);
06039     vec_copy((float*) &trimesh[i].c2, &vnc[ind + 24]);
06040   }
06041   rtBufferUnmap(buf); // triangle list is complete, unmap buffer
06042 
06043   RTERR( rtGeometryCreate(ctx, &geom) );
06044   RTERR( rtGeometrySetPrimitiveCount(geom, numtris) );
06045   RTERR( rtGeometrySetBoundingBoxProgram(geom, tricolor_bbox_pgm) );
06046   RTERR( rtGeometrySetIntersectionProgram(geom, tricolor_isct_pgm) );
06047 
06048   // this buffer is associated only with this particular geometry node
06049   RTvariable buf_v;
06050   RTERR( rtGeometryDeclareVariable(geom, "tricolor_buffer", &buf_v) );
06051   RTERR( rtVariableSetObject(buf_v, buf) );
06052 
06053   // create a geometry instance and bind materials to this geometry
06054   RTERR( rtGeometryInstanceCreate(ctx, &instance) );
06055   RTERR( rtGeometryInstanceSetGeometry(instance, geom) );
06056 //  RTERR( rtGeometryInstanceSetMaterialCount(instance, 1) );
06057 
06058   set_material(instance, matindex, NULL);
06059 
06060   append_objects(buf, geom, instance);
06061 }
06062 
06063 
06064 #if defined(ORT_USERTXAPIS)
06065 void OptiXRenderer::trimesh_c4n3v3_hwtri(Matrix4 & wtrans, 
06066                                          int numverts, const float *cnv, 
06067                                          int numfacets, const int * facets,
06068                                          int matindex) {
06069   if (!context_created) return;
06070   if (verbose == RT_VERB_DEBUG) printf("OptiXRenderer) creating trimesh_c4n3v3_hwtri: %d...\n", numfacets);
06071   trimesh_c4u_n3b_v3f_cnt += numfacets;
06072 
06073   RTbuffer vbuf, nbuf, cbuf;
06074   RTgeometryinstance instance_hwtri;
06075   RTgeometrytriangles geom_hwtri;
06076 
06077   // Create and fill vertex/normal/color buffers
06078   float3 *vertices; 
06079   uint4 *normals;
06080   uchar4 *colors;
06081   hwtri_alloc_bufs_v3f_n4u4_c4u(ctx, numfacets, vbuf, vertices, nbuf, normals, 
06082                                 cbuf, numfacets * 3, colors, NULL);
06083 
06084   int i, ind, tcnt;
06085   for (i=0,ind=0,tcnt=0; i<numfacets; i++,ind+=3) {
06086     int taddr = 3 * tcnt;
06087 
06088     int v0 = facets[ind    ] * 10;
06089     int v1 = facets[ind + 1] * 10;
06090     int v2 = facets[ind + 2] * 10;
06091 
06092     // transform to eye coordinates
06093     wtrans.multpoint3d(cnv + v0 + 7, (float*) &vertices[taddr + 0]);
06094     wtrans.multpoint3d(cnv + v1 + 7, (float*) &vertices[taddr + 1]);
06095     wtrans.multpoint3d(cnv + v2 + 7, (float*) &vertices[taddr + 2]);
06096 
06097     // Compute geometric normal, detect and cull degenerate triangles
06098     float3 Ng;
06099     if (hwtri_test_calc_Ngeom(&vertices[taddr], Ng)) {
06100       continue; // cull any triangle that fails degeneracy tests
06101     }
06102 
06103     float3 n0, n1, n2;
06104     wtrans.multnorm3d(cnv + v0 + 4, (float*) &n0);
06105     wtrans.multnorm3d(cnv + v1 + 4, (float*) &n1);
06106     wtrans.multnorm3d(cnv + v2 + 4, (float*) &n2);
06107 
06108     // Pack normals
06109     normals[tcnt].x = packNormal(Ng);
06110     normals[tcnt].y = packNormal(n0);
06111     normals[tcnt].z = packNormal(n1);
06112     normals[tcnt].w = packNormal(n2);
06113 
06114     // convert color format
06115     colors[taddr + 0].x = cnv[v0 + 0] * 255.0f;
06116     colors[taddr + 0].y = cnv[v0 + 1] * 255.0f;
06117     colors[taddr + 0].z = cnv[v0 + 2] * 255.0f;
06118 
06119     colors[taddr + 1].x = cnv[v1 + 0] * 255.0f;
06120     colors[taddr + 1].y = cnv[v1 + 1] * 255.0f;
06121     colors[taddr + 1].z = cnv[v1 + 2] * 255.0f;
06122 
06123     colors[taddr + 2].x = cnv[v2 + 0] * 255.0f;
06124     colors[taddr + 2].y = cnv[v2 + 1] * 255.0f;
06125     colors[taddr + 2].z = cnv[v2 + 2] * 255.0f;
06126 
06127     tcnt++; // count non-culled triangles
06128   }
06129 
06130   rtBufferUnmap(vbuf);
06131   rtBufferUnmap(nbuf);
06132   rtBufferUnmap(cbuf);
06133 
06134   RTERR( rtGeometryTrianglesCreate(ctx, &geom_hwtri) );
06135   RTERR( rtGeometryTrianglesSetPrimitiveCount(geom_hwtri, tcnt) );
06136   RTERR( rtGeometryTrianglesSetVertices(geom_hwtri, tcnt * 3, vbuf, 
06137                                         0, sizeof(float3), RT_FORMAT_FLOAT3) );
06138 #if defined(VMDOPTIXRTXRELEASEBUFS)
06139   RTERR( rtGeometryTrianglesSetBuildFlags(geom_hwtri, RT_GEOMETRY_BUILD_FLAG_RELEASE_BUFFERS) );
06140 #else
06141   append_buffer(vbuf);
06142 #endif
06143 
06144   // create a geometry instance and bind materials to this geometry
06145   RTERR( rtGeometryInstanceCreate(ctx, &instance_hwtri) );
06146   RTERR( rtGeometryInstanceSetGeometryTriangles(instance_hwtri, geom_hwtri) );
06147 
06148   // Enable per-vertex normals, enable per-vertex colors
06149   hwtri_set_vertex_flags(ctx, instance_hwtri, nbuf, cbuf, 1, 1);
06150 
06151   // We have to pass the explicit hardware triangle parameter for this geometry
06152   set_material(instance_hwtri, matindex, NULL, 1);
06153 
06154   // The vertex buffer is released automatically after construction. 
06155   // We need to keep track of normal and color buffers for ourselves.
06156   append_objects(nbuf, cbuf, geom_hwtri, instance_hwtri);
06157 }
06158 #endif
06159 
06160 
06161 void OptiXRenderer::trimesh_c4n3v3(Matrix4 & wtrans, 
06162                                    int numverts, const float *cnv, 
06163                                    int numfacets, const int * facets,
06164                                    int matindex) {
06165   if (!context_created) return;
06166 
06167 #if defined(ORT_USERTXAPIS)
06168   // OptiX 5.2 hardware-accelerated triangle API
06169   if (hwtri_enabled) {
06170     trimesh_c4n3v3_hwtri(wtrans, numverts, cnv, numfacets, facets, matindex);
06171     return;
06172   }
06173 #endif
06174 
06175   if (verbose == RT_VERB_DEBUG) printf("OptiXRenderer) creating trimesh_c4n3v3: %d...\n", numfacets);
06176   trimesh_c4u_n3b_v3f_cnt += numfacets;
06177 
06178   int i, ind;
06179   RTbuffer buf;
06180   RTgeometry geom;
06181   RTgeometryinstance instance;
06182   vmd_tricolor *trimesh;
06183 
06184   // create and fill the OptiX trimesh memory buffer
06185   rtBufferCreate(ctx, RT_BUFFER_INPUT, &buf);
06186   rtBufferSetFormat(buf, RT_FORMAT_USER);
06187   rtBufferSetElementSize(buf, sizeof(vmd_tricolor));
06188   rtBufferSetSize1D(buf, numfacets);
06189   // rtBufferValidate(buf);
06190   rtBufferMap(buf, (void **) &trimesh); // map buffer for writing by host
06191 
06192   for (i=0,ind=0; i<numfacets; i++,ind+=3) {
06193     int v0 = facets[ind    ] * 10;
06194     int v1 = facets[ind + 1] * 10;
06195     int v2 = facets[ind + 2] * 10;
06196 
06197     // transform to eye coordinates
06198     wtrans.multpoint3d(cnv + v0 + 7, (float*) &trimesh[i].v0);
06199     wtrans.multpoint3d(cnv + v1 + 7, (float*) &trimesh[i].v1);
06200     wtrans.multpoint3d(cnv + v2 + 7, (float*) &trimesh[i].v2);
06201 
06202     wtrans.multnorm3d(cnv + v0 + 4, (float*) &trimesh[i].n0);
06203     wtrans.multnorm3d(cnv + v1 + 4, (float*) &trimesh[i].n1);
06204     wtrans.multnorm3d(cnv + v2 + 4, (float*) &trimesh[i].n2);
06205 
06206     vec_copy((float*) &trimesh[i].c0, cnv + v0);
06207     vec_copy((float*) &trimesh[i].c1, cnv + v1);
06208     vec_copy((float*) &trimesh[i].c2, cnv + v2);
06209   }
06210   rtBufferUnmap(buf); // triangle list is complete, unmap buffer
06211 
06212   RTERR( rtGeometryCreate(ctx, &geom) );
06213   RTERR( rtGeometrySetPrimitiveCount(geom, numfacets) );
06214   RTERR( rtGeometrySetBoundingBoxProgram(geom, tricolor_bbox_pgm) );
06215   RTERR( rtGeometrySetIntersectionProgram(geom, tricolor_isct_pgm) );
06216 
06217   // this buffer is associated only with this particular geometry node
06218   RTvariable buf_v;
06219   RTERR( rtGeometryDeclareVariable(geom, "tricolor_buffer", &buf_v) );
06220   RTERR( rtVariableSetObject(buf_v, buf) );
06221 
06222   // create a geometry instance and bind materials to this geometry
06223   RTERR( rtGeometryInstanceCreate(ctx, &instance) );
06224   RTERR( rtGeometryInstanceSetGeometry(instance, geom) );
06225 
06226   set_material(instance, matindex, NULL);
06227 
06228   append_objects(buf, geom, instance);
06229 }
06230 
06231 
06232 #if defined(ORT_USERTXAPIS)
06233 // 
06234 // This implementation translates from the most-compact host representation
06235 // to a GPU-specific organization that balances performance vs. memory 
06236 // storage efficiency.
06237 //
06238 void OptiXRenderer::trimesh_c4u_n3b_v3f_hwtri(Matrix4 & wtrans, 
06239                                               const unsigned char *c, 
06240                                               const signed char *n, 
06241                                               const float *v, int numfacets, 
06242                                               int matindex) {
06243   if (!context_created) return;
06244   if (verbose == RT_VERB_DEBUG) printf("OptiXRenderer) creating trimesh_c4u_n3b_v3f_hwtri: %d...\n", numfacets);
06245   trimesh_c4u_n3b_v3f_cnt += numfacets;
06246 
06247   RTbuffer vbuf, nbuf, cbuf;
06248   RTgeometryinstance instance_hwtri;
06249   RTgeometrytriangles geom_hwtri;
06250 
06251   // Create and fill vertex/normal/color buffers
06252   float3 *vertices; 
06253   uint4 *normals;
06254   uchar4 *colors;
06255   hwtri_alloc_bufs_v3f_n4u4_c4u(ctx, numfacets, vbuf, vertices, nbuf, normals, 
06256                                 cbuf, numfacets * 3, colors, NULL);
06257 
06258   const float ci2f = 1.0f / 255.0f;
06259   const float cn2f = 1.0f / 127.5f;
06260   int i, j, ind, tcnt;
06261   for (ind=0,i=0,j=0,tcnt=0; ind<numfacets; ind++,i+=9,j+=12) {
06262     float norm[9];
06263     int taddr = 3 * tcnt;
06264 
06265     // transform to eye coordinates
06266     wtrans.multpoint3d(v + i    , (float*) &vertices[taddr + 0]);
06267     wtrans.multpoint3d(v + i + 3, (float*) &vertices[taddr + 1]);
06268     wtrans.multpoint3d(v + i + 6, (float*) &vertices[taddr + 2]);
06269 
06270     // Compute geometric normal, detect and cull degenerate triangles
06271     float3 Ng;
06272     if (hwtri_test_calc_Ngeom(&vertices[taddr], Ng)) {
06273       continue; // cull any triangle that fails degeneracy tests
06274     }
06275 
06276     // conversion from GLbyte format, Table 2.6, p. 44 of OpenGL spec 1.2.1
06277     // float = (2c+1)/(2^8-1)
06278     norm[0] = n[i    ] * cn2f + ci2f;
06279     norm[1] = n[i + 1] * cn2f + ci2f;
06280     norm[2] = n[i + 2] * cn2f + ci2f;
06281     norm[3] = n[i + 3] * cn2f + ci2f;
06282     norm[4] = n[i + 4] * cn2f + ci2f;
06283     norm[5] = n[i + 5] * cn2f + ci2f;
06284     norm[6] = n[i + 6] * cn2f + ci2f;
06285     norm[7] = n[i + 7] * cn2f + ci2f;
06286     norm[8] = n[i + 8] * cn2f + ci2f;
06287 
06288     // transform normals
06289     float3 n0, n1, n2;
06290     wtrans.multnorm3d(&norm[0], (float*) &n0);
06291     wtrans.multnorm3d(&norm[3], (float*) &n1);
06292     wtrans.multnorm3d(&norm[6], (float*) &n2);
06293 
06294     // Pack normals
06295     normals[tcnt].x = packNormal(Ng);
06296     normals[tcnt].y = packNormal(n0);
06297     normals[tcnt].z = packNormal(n1);
06298     normals[tcnt].w = packNormal(n2);
06299 
06300     memcpy(&colors[tcnt * 3], &c[j], 12); // copy colors (same memory format)
06301 
06302     tcnt++; // count non-culled triangles
06303   }
06304 
06305   rtBufferUnmap(vbuf);
06306   rtBufferUnmap(nbuf);
06307   rtBufferUnmap(cbuf);
06308 
06309   RTERR( rtGeometryTrianglesCreate(ctx, &geom_hwtri) );
06310   RTERR( rtGeometryTrianglesSetPrimitiveCount(geom_hwtri, tcnt) );
06311   RTERR( rtGeometryTrianglesSetVertices(geom_hwtri, tcnt * 3, vbuf, 
06312                                         0, sizeof(float3), RT_FORMAT_FLOAT3) );
06313 #if defined(VMDOPTIXRTXRELEASEBUFS)
06314   RTERR( rtGeometryTrianglesSetBuildFlags(geom_hwtri, RT_GEOMETRY_BUILD_FLAG_RELEASE_BUFFERS) );
06315 #else
06316   append_buffer(vbuf);
06317 #endif
06318 
06319   // create a geometry instance and bind materials to this geometry
06320   RTERR( rtGeometryInstanceCreate(ctx, &instance_hwtri) );
06321   RTERR( rtGeometryInstanceSetGeometryTriangles(instance_hwtri, geom_hwtri) );
06322 
06323   // Enable per-vertex normals, enable per-vertex colors
06324   hwtri_set_vertex_flags(ctx, instance_hwtri, nbuf, cbuf, 1, 1);
06325 
06326   // We have to pass the explicit hardware triangle parameter for this geometry
06327   set_material(instance_hwtri, matindex, NULL, 1);
06328 
06329   // The vertex buffer is released automatically after construction. 
06330   // We need to keep track of normal and color buffers for ourselves.
06331   append_objects(nbuf, cbuf, geom_hwtri, instance_hwtri);
06332 }
06333 #endif
06334 
06335 
06336 // 
06337 // This implementation translates from the most-compact host representation
06338 // to a GPU-specific organization that balances performance vs. memory 
06339 // storage efficiency.
06340 //
06341 void OptiXRenderer::trimesh_c4u_n3b_v3f(Matrix4 & wtrans, 
06342                                         const unsigned char *c, 
06343                                         const signed char *n, const float *v, 
06344                                         int numfacets, int matindex) {
06345   if (!context_created) return;
06346 
06347 #if defined(ORT_USERTXAPIS)
06348   // OptiX RTX hardware-accelerated triangle API
06349   if (hwtri_enabled) {
06350     trimesh_c4u_n3b_v3f_hwtri(wtrans, c, n, v, numfacets, matindex);
06351     return;
06352   }
06353 #endif
06354 
06355   if (verbose == RT_VERB_DEBUG) printf("OptiXRenderer) creating trimesh_c4u_n3b_v3f: %d...\n", numfacets);
06356   trimesh_n3b_v3f_cnt += numfacets;
06357 
06358   int i, j, ind;
06359   RTbuffer buf;
06360   RTgeometry geom;
06361   RTgeometryinstance instance;
06362   vmd_trimesh_c4u_n3b_v3f *trimesh;
06363 
06364   // create and fill the OptiX trimesh memory buffer
06365   rtBufferCreate(ctx, RT_BUFFER_INPUT, &buf);
06366   rtBufferSetFormat(buf, RT_FORMAT_USER);
06367   rtBufferSetElementSize(buf, sizeof(vmd_trimesh_c4u_n3b_v3f));
06368   rtBufferSetSize1D(buf, numfacets);
06369   // rtBufferValidate(buf);
06370   rtBufferMap(buf, (void **) &trimesh); // map buffer for writing by host
06371 
06372   const float ci2f = 1.0f / 255.0f;
06373   const float cn2f = 1.0f / 127.5f;
06374   for (ind=0,i=0,j=0; ind<numfacets; ind++,i+=9,j+=12) {
06375     float norm[9];
06376 
06377     // transform to eye coordinates
06378     wtrans.multpoint3d(v + i    , (float*) &trimesh[ind].v0);
06379     wtrans.multpoint3d(v + i + 3, (float*) &trimesh[ind].v1);
06380     wtrans.multpoint3d(v + i + 6, (float*) &trimesh[ind].v2);
06381 
06382     // conversion from GLbyte format, Table 2.6, p. 44 of OpenGL spec 1.2.1
06383     // float = (2c+1)/(2^8-1)
06384     norm[0] = n[i    ] * cn2f + ci2f;
06385     norm[1] = n[i + 1] * cn2f + ci2f;
06386     norm[2] = n[i + 2] * cn2f + ci2f;
06387     norm[3] = n[i + 3] * cn2f + ci2f;
06388     norm[4] = n[i + 4] * cn2f + ci2f;
06389     norm[5] = n[i + 5] * cn2f + ci2f;
06390     norm[6] = n[i + 6] * cn2f + ci2f;
06391     norm[7] = n[i + 7] * cn2f + ci2f;
06392     norm[8] = n[i + 8] * cn2f + ci2f;
06393 
06394     // transform normals
06395     float3 tmpn;
06396     wtrans.multnorm3d(&norm[0], (float*) &tmpn);
06397     tmpn = tmpn * 127.5f - 0.5f;
06398     trimesh[ind].n0 = make_char4(tmpn.x, tmpn.y, tmpn.z, 0);
06399     wtrans.multnorm3d(&norm[3], (float*) &tmpn);
06400     tmpn = tmpn * 127.5f - 0.5f;
06401     trimesh[ind].n1 = make_char4(tmpn.x, tmpn.y, tmpn.z, 0);
06402     wtrans.multnorm3d(&norm[6], (float*) &tmpn);
06403     tmpn = tmpn * 127.5f - 0.5f;
06404     trimesh[ind].n2 = make_char4(tmpn.x, tmpn.y, tmpn.z, 0);
06405 
06406     memcpy(&trimesh[ind].c0, &c[j  ], 4);
06407     memcpy(&trimesh[ind].c1, &c[j+4], 4);
06408     memcpy(&trimesh[ind].c2, &c[j+8], 4);
06409   }
06410   rtBufferUnmap(buf); // triangle list is complete, unmap buffer
06411 
06412   RTERR( rtGeometryCreate(ctx, &geom) );
06413   RTERR( rtGeometrySetPrimitiveCount(geom, numfacets) );
06414   RTERR( rtGeometrySetBoundingBoxProgram(geom, trimesh_c4u_n3b_v3f_bbox_pgm) );
06415   RTERR( rtGeometrySetIntersectionProgram(geom, trimesh_c4u_n3b_v3f_isct_pgm) );
06416 
06417   // this trimesh buffer is associated only with this particular geometry node
06418   RTvariable buf_v;
06419   RTERR( rtGeometryDeclareVariable(geom, "trimesh_c4u_n3b_v3f_buffer", &buf_v) );
06420   RTERR( rtVariableSetObject(buf_v, buf) );
06421 
06422   // create a geometry instance and bind materials to this geometry
06423   RTERR( rtGeometryInstanceCreate(ctx, &instance) );
06424   RTERR( rtGeometryInstanceSetGeometry(instance, geom) );
06425 
06426   set_material(instance, matindex, NULL);
06427 
06428   append_objects(buf, geom, instance);
06429 }
06430 
06431 
06432 #if defined(ORT_USERTXAPIS)
06433 void OptiXRenderer::trimesh_c4u_n3f_v3f_hwtri(Matrix4 & wtrans, 
06434                                               const unsigned char *c, 
06435                                               const float *n, const float *v, 
06436                                               int numfacets, int matindex) {
06437   if (!context_created) return;
06438   if (verbose == RT_VERB_DEBUG) printf("OptiXRenderer) creating trimesh_c4u_n3f_v3f: %d...\n", numfacets);
06439   tricolor_cnt += numfacets;
06440 
06441   RTbuffer vbuf, nbuf, cbuf;
06442   RTgeometryinstance instance_hwtri;
06443   RTgeometrytriangles geom_hwtri;
06444   
06445   // Create and fill vertex/normal/color buffers
06446   float3 *vertices; 
06447   uint4 *normals;
06448   uchar4 *colors;
06449   hwtri_alloc_bufs_v3f_n4u4_c4u(ctx, numfacets, vbuf, vertices, nbuf, normals, 
06450                                 cbuf, 1, colors, NULL);
06451 
06452   int i, j, ind, tcnt;
06453   for (ind=0,i=0,j=0,tcnt=0; ind<numfacets; ind++,i+=9,j+=12) {
06454     int taddr = 3 * tcnt;
06455 
06456     // transform to eye coordinates
06457     wtrans.multpoint3d(v + i    , (float*) &vertices[taddr + 0]);
06458     wtrans.multpoint3d(v + i + 3, (float*) &vertices[taddr + 1]);
06459     wtrans.multpoint3d(v + i + 6, (float*) &vertices[taddr + 2]);
06460 
06461     // Compute geometric normal, detect and cull degenerate triangles
06462     float3 Ng;
06463     if (hwtri_test_calc_Ngeom(&vertices[taddr], Ng)) {
06464       continue; // cull any triangle that fails degeneracy tests
06465     }
06466 
06467     float3 n0, n1, n2;
06468     wtrans.multnorm3d(n + i    , (float*) &n0);
06469     wtrans.multnorm3d(n + i + 3, (float*) &n1);
06470     wtrans.multnorm3d(n + i + 6, (float*) &n2);
06471 
06472     // Pack normals
06473     normals[tcnt].x = packNormal(Ng);
06474     normals[tcnt].y = packNormal(n0);
06475     normals[tcnt].z = packNormal(n1);
06476     normals[tcnt].w = packNormal(n2);
06477 
06478     memcpy(&colors[taddr + 0], &c[j  ], sizeof(uchar4));
06479     memcpy(&colors[taddr + 1], &c[j+4], sizeof(uchar4));
06480     memcpy(&colors[taddr + 2], &c[j+8], sizeof(uchar4));
06481 
06482     tcnt++; // count non-culled triangles
06483   }
06484 
06485   rtBufferUnmap(vbuf);
06486   rtBufferUnmap(nbuf);
06487   rtBufferUnmap(cbuf);
06488 
06489   RTERR( rtGeometryTrianglesCreate(ctx, &geom_hwtri) );
06490   RTERR( rtGeometryTrianglesSetPrimitiveCount(geom_hwtri, tcnt) );
06491   RTERR( rtGeometryTrianglesSetVertices(geom_hwtri, tcnt * 3, vbuf, 
06492                                         0, sizeof(float3), RT_FORMAT_FLOAT3) );
06493 #if defined(VMDOPTIXRTXRELEASEBUFS)
06494   RTERR( rtGeometryTrianglesSetBuildFlags(geom_hwtri, RT_GEOMETRY_BUILD_FLAG_RELEASE_BUFFERS) );
06495 #else
06496   append_buffer(vbuf);
06497 #endif
06498 
06499   // create a geometry instance and bind materials to this geometry
06500   RTERR( rtGeometryInstanceCreate(ctx, &instance_hwtri) );
06501   RTERR( rtGeometryInstanceSetGeometryTriangles(instance_hwtri, geom_hwtri) );
06502 
06503   // Enable per-vertex normals, enable per-vertex colors
06504   hwtri_set_vertex_flags(ctx, instance_hwtri, nbuf, cbuf, 1, 1);
06505 
06506   // We have to pass the explicit hardware triangle parameter for this geometry
06507   set_material(instance_hwtri, matindex, NULL, 1);
06508 
06509   // The vertex buffer is released automatically after construction. 
06510   // We need to keep track of normal and color buffers for ourselves.
06511   append_objects(nbuf, cbuf, geom_hwtri, instance_hwtri);
06512 }
06513 #endif
06514 
06515 
06516 void OptiXRenderer::trimesh_c4u_n3f_v3f(Matrix4 & wtrans, 
06517                                         const unsigned char *c, 
06518                                         const float *n, const float *v, 
06519                                         int numfacets, int matindex) {
06520   if (!context_created) return;
06521 
06522 #if defined(ORT_USERTXAPIS)
06523   // OptiX RTX hardware-accelerated triangle API
06524   if (hwtri_enabled) {
06525     trimesh_c4u_n3f_v3f_hwtri(wtrans, c, n, v, numfacets, matindex);
06526     return;
06527   }
06528 #endif
06529 
06530   if (verbose == RT_VERB_DEBUG) printf("OptiXRenderer) creating trimesh_c4u_n3f_v3f: %d...\n", numfacets);
06531   tricolor_cnt += numfacets;
06532 
06533   int i, j, ind;
06534   RTbuffer buf;
06535   RTgeometry geom;
06536   RTgeometryinstance instance;
06537   vmd_tricolor *trimesh;
06538 
06539   // create and fill the OptiX trimesh memory buffer
06540   rtBufferCreate(ctx, RT_BUFFER_INPUT, &buf);
06541   rtBufferSetFormat(buf, RT_FORMAT_USER);
06542   rtBufferSetElementSize(buf, sizeof(vmd_tricolor));
06543   rtBufferSetSize1D(buf, numfacets);
06544   // rtBufferValidate(buf);
06545   rtBufferMap(buf, (void **) &trimesh); // map buffer for writing by host
06546 
06547   const float ci2f = 1.0f / 255.0f;
06548   for (ind=0,i=0,j=0; ind<numfacets; ind++,i+=9,j+=12) {
06549     // transform to eye coordinates
06550     wtrans.multpoint3d(v + i    , (float*) &trimesh[ind].v0);
06551     wtrans.multpoint3d(v + i + 3, (float*) &trimesh[ind].v1);
06552     wtrans.multpoint3d(v + i + 6, (float*) &trimesh[ind].v2);
06553 
06554     wtrans.multnorm3d(n + i    , (float*) &trimesh[ind].n0);
06555     wtrans.multnorm3d(n + i + 3, (float*) &trimesh[ind].n1);
06556     wtrans.multnorm3d(n + i + 6, (float*) &trimesh[ind].n2);
06557 
06558     // conversion from GLubyte format, Table 2.6, p. 44 of OpenGL spec 1.2.1
06559     // float = c/(2^8-1)
06560     float col[9];
06561     col[0] = c[j     ] * ci2f;
06562     col[1] = c[j +  1] * ci2f;
06563     col[2] = c[j +  2] * ci2f;
06564     col[3] = c[j +  4] * ci2f;
06565     col[4] = c[j +  5] * ci2f;
06566     col[5] = c[j +  6] * ci2f;
06567     col[6] = c[j +  8] * ci2f;
06568     col[7] = c[j +  9] * ci2f;
06569     col[8] = c[j + 10] * ci2f;
06570 
06571     vec_copy((float*) &trimesh[ind].c0, &col[0]);
06572     vec_copy((float*) &trimesh[ind].c1, &col[3]);
06573     vec_copy((float*) &trimesh[ind].c2, &col[6]);
06574   }
06575   rtBufferUnmap(buf); // triangle list is complete, unmap buffer
06576 
06577   RTERR( rtGeometryCreate(ctx, &geom) );
06578   RTERR( rtGeometrySetPrimitiveCount(geom, numfacets) );
06579   RTERR( rtGeometrySetBoundingBoxProgram(geom, tricolor_bbox_pgm) );
06580   RTERR( rtGeometrySetIntersectionProgram(geom, tricolor_isct_pgm) );
06581 
06582   // this buffer is associated only with this particular geometry node
06583   RTvariable buf_v;
06584   RTERR( rtGeometryDeclareVariable(geom, "tricolor_buffer", &buf_v) );
06585   RTERR( rtVariableSetObject(buf_v, buf) );
06586 
06587   // create a geometry instance and bind materials to this geometry
06588   RTERR( rtGeometryInstanceCreate(ctx, &instance) );
06589   RTERR( rtGeometryInstanceSetGeometry(instance, geom) );
06590 
06591   set_material(instance, matindex, NULL);
06592 
06593   append_objects(buf, geom, instance);
06594 }
06595 
06596 
06597 #if defined(ORT_USERTXAPIS)
06598 void OptiXRenderer::trimesh_n3b_v3f_hwtri(Matrix4 & wtrans, 
06599                                           const float *uniform_color, 
06600                                           const signed char *n, const float *v, 
06601                                           int numfacets, int matindex) {
06602   if (!context_created) return;
06603   if (verbose == RT_VERB_DEBUG) printf("OptiXRenderer) creating trimesh_n3b_v3f_hwtri: %d...\n", numfacets);
06604   trimesh_n3b_v3f_cnt += numfacets;
06605 
06606   RTbuffer vbuf, nbuf, cbuf;
06607   RTgeometryinstance instance_hwtri;
06608   RTgeometrytriangles geom_hwtri;
06609 
06610   // Create and fill vertex/normal/color buffers
06611   float3 *vertices; 
06612   uint4 *normals;
06613   uchar4 *colors;
06614   hwtri_alloc_bufs_v3f_n4u4_c4u(ctx, numfacets, vbuf, vertices, nbuf, normals, 
06615                                 cbuf, 1, colors, uniform_color);
06616 
06617   const float ci2f = 1.0f / 255.0f;
06618   const float cn2f = 1.0f / 127.5f;
06619   int i, ind, tcnt;
06620   for (ind=0,i=0,tcnt=0; ind<numfacets; ind++,i+=9) {
06621     float norm[9];
06622     int taddr = 3 * tcnt;
06623 
06624     // transform to eye coordinates
06625     wtrans.multpoint3d(v + i    , (float*) &vertices[taddr + 0]);
06626     wtrans.multpoint3d(v + i + 3, (float*) &vertices[taddr + 1]);
06627     wtrans.multpoint3d(v + i + 6, (float*) &vertices[taddr + 2]);
06628 
06629     // Compute geometric normal, detect and cull degenerate triangles
06630     float3 Ng;
06631     if (hwtri_test_calc_Ngeom(&vertices[taddr], Ng)) {
06632       continue; // cull any triangle that fails degeneracy tests
06633     }
06634 
06635     // conversion from GLbyte format, Table 2.6, p. 44 of OpenGL spec 1.2.1
06636     // float = (2c+1)/(2^8-1)
06637     norm[0] = n[i    ] * cn2f + ci2f;
06638     norm[1] = n[i + 1] * cn2f + ci2f;
06639     norm[2] = n[i + 2] * cn2f + ci2f;
06640     norm[3] = n[i + 3] * cn2f + ci2f;
06641     norm[4] = n[i + 4] * cn2f + ci2f;
06642     norm[5] = n[i + 5] * cn2f + ci2f;
06643     norm[6] = n[i + 6] * cn2f + ci2f;
06644     norm[7] = n[i + 7] * cn2f + ci2f;
06645     norm[8] = n[i + 8] * cn2f + ci2f;
06646 
06647     // transform normals
06648     float3 n0, n1, n2;
06649     wtrans.multnorm3d(&norm[0], (float*) &n0);
06650     wtrans.multnorm3d(&norm[3], (float*) &n1);
06651     wtrans.multnorm3d(&norm[6], (float*) &n2);
06652 
06653     // Pack normals
06654     normals[tcnt].x = packNormal(Ng);
06655     normals[tcnt].y = packNormal(n0);
06656     normals[tcnt].z = packNormal(n1);
06657     normals[tcnt].w = packNormal(n2);
06658 
06659     tcnt++; // count non-culled triangles
06660   }
06661 
06662   rtBufferUnmap(vbuf);
06663   rtBufferUnmap(nbuf);
06664   rtBufferUnmap(cbuf);
06665 
06666   RTERR( rtGeometryTrianglesCreate(ctx, &geom_hwtri) );
06667   RTERR( rtGeometryTrianglesSetPrimitiveCount(geom_hwtri, tcnt) );
06668   RTERR( rtGeometryTrianglesSetVertices(geom_hwtri, tcnt * 3, vbuf, 
06669                                         0, sizeof(float3), RT_FORMAT_FLOAT3) );
06670 #if defined(VMDOPTIXRTXRELEASEBUFS)
06671   RTERR( rtGeometryTrianglesSetBuildFlags(geom_hwtri, RT_GEOMETRY_BUILD_FLAG_RELEASE_BUFFERS) );
06672 #else
06673   append_buffer(vbuf);
06674 #endif
06675 
06676   // create a geometry instance and bind materials to this geometry
06677   RTERR( rtGeometryInstanceCreate(ctx, &instance_hwtri) );
06678   RTERR( rtGeometryInstanceSetGeometryTriangles(instance_hwtri, geom_hwtri) );
06679 
06680   // Enable per-vertex normals, disable per-vertex colors (use uniform color) 
06681   hwtri_set_vertex_flags(ctx, instance_hwtri, nbuf, cbuf, 1, 0);
06682 
06683   // We have to pass the explicit hardware triangle parameter for this geometry
06684   set_material(instance_hwtri, matindex, uniform_color, 1);
06685 
06686   // The vertex buffer is released automatically after construction. 
06687   // We need to keep track of normal and color buffers for ourselves.
06688   append_objects(nbuf, cbuf, geom_hwtri, instance_hwtri);
06689 }
06690 #endif
06691 
06692 
06693 void OptiXRenderer::trimesh_n3b_v3f(Matrix4 & wtrans, 
06694                                     const float *uniform_color, 
06695                                     const signed char *n, const float *v, 
06696                                     int numfacets, int matindex) {
06697   if (!context_created) return;
06698 
06699 #if defined(ORT_USERTXAPIS)
06700   // OptiX RTX hardware-accelerated triangle API
06701   if (hwtri_enabled) {
06702     trimesh_n3b_v3f_hwtri(wtrans, uniform_color, n, v, numfacets, matindex);
06703     return;
06704   }
06705 #endif
06706 
06707   if (verbose == RT_VERB_DEBUG) printf("OptiXRenderer) creating trimesh_n3b_v3f: %d...\n", numfacets);
06708   trimesh_n3b_v3f_cnt += numfacets;
06709 
06710   int i, ind;
06711   RTbuffer buf;
06712   RTgeometry geom;
06713   RTgeometryinstance instance;
06714   vmd_trimesh_n3b_v3f *trimesh;
06715 
06716   // create and fill the OptiX trimesh memory buffer
06717   rtBufferCreate(ctx, RT_BUFFER_INPUT, &buf);
06718   rtBufferSetFormat(buf, RT_FORMAT_USER);
06719   rtBufferSetElementSize(buf, sizeof(vmd_trimesh_n3b_v3f));
06720   rtBufferSetSize1D(buf, numfacets);
06721   // rtBufferValidate(buf);
06722   rtBufferMap(buf, (void **) &trimesh); // map buffer for writing by host
06723 
06724   const float ci2f = 1.0f / 255.0f;
06725   const float cn2f = 1.0f / 127.5f;
06726   for (ind=0,i=0; ind<numfacets; ind++,i+=9) {
06727     float norm[9];
06728 
06729     // transform to eye coordinates
06730     wtrans.multpoint3d(v + i    , (float*) &trimesh[ind].v0);
06731     wtrans.multpoint3d(v + i + 3, (float*) &trimesh[ind].v1);
06732     wtrans.multpoint3d(v + i + 6, (float*) &trimesh[ind].v2);
06733 
06734     // conversion from GLbyte format, Table 2.6, p. 44 of OpenGL spec 1.2.1
06735     // float = (2c+1)/(2^8-1)
06736     norm[0] = n[i    ] * cn2f + ci2f;
06737     norm[1] = n[i + 1] * cn2f + ci2f;
06738     norm[2] = n[i + 2] * cn2f + ci2f;
06739     norm[3] = n[i + 3] * cn2f + ci2f;
06740     norm[4] = n[i + 4] * cn2f + ci2f;
06741     norm[5] = n[i + 5] * cn2f + ci2f;
06742     norm[6] = n[i + 6] * cn2f + ci2f;
06743     norm[7] = n[i + 7] * cn2f + ci2f;
06744     norm[8] = n[i + 8] * cn2f + ci2f;
06745 
06746     // transform normals
06747     float3 tmpn;
06748     wtrans.multnorm3d(&norm[0], (float*) &tmpn);
06749     tmpn = tmpn * 127.5f - 0.5f;
06750     trimesh[ind].n0 = make_char4(tmpn.x, tmpn.y, tmpn.z, 0);
06751     wtrans.multnorm3d(&norm[3], (float*) &tmpn);
06752     tmpn = tmpn * 127.5f - 0.5f;
06753     trimesh[ind].n1 = make_char4(tmpn.x, tmpn.y, tmpn.z, 0);
06754     wtrans.multnorm3d(&norm[6], (float*) &tmpn);
06755     tmpn = tmpn * 127.5f - 0.5f;
06756     trimesh[ind].n2 = make_char4(tmpn.x, tmpn.y, tmpn.z, 0);
06757   }
06758   rtBufferUnmap(buf); // triangle list is complete, unmap buffer
06759 
06760   RTERR( rtGeometryCreate(ctx, &geom) );
06761   RTERR( rtGeometrySetPrimitiveCount(geom, numfacets) );
06762   RTERR( rtGeometrySetBoundingBoxProgram(geom, trimesh_n3b_v3f_bbox_pgm) );
06763   RTERR( rtGeometrySetIntersectionProgram(geom, trimesh_n3b_v3f_isct_pgm) );
06764 
06765   // this buffer is associated only with this particular geometry node
06766   RTvariable buf_v;
06767   RTERR( rtGeometryDeclareVariable(geom, "trimesh_n3b_v3f_buffer", &buf_v) );
06768   RTERR( rtVariableSetObject(buf_v, buf) );
06769 
06770   // create a geometry instance and bind materials to this geometry
06771   RTERR( rtGeometryInstanceCreate(ctx, &instance) );
06772   RTERR( rtGeometryInstanceSetGeometry(instance, geom) );
06773 
06774   set_material(instance, matindex, uniform_color);
06775 
06776   append_objects(buf, geom, instance);
06777 }
06778 
06779 
06780 #if defined(ORT_USERTXAPIS)
06781 void OptiXRenderer::trimesh_n3f_v3f_hwtri(Matrix4 & wtrans, 
06782                                           const float *uniform_color,
06783                                           const float *n, const float *v, 
06784                                           int numfacets, int matindex) {
06785   if (!context_created) return;
06786   if (verbose == RT_VERB_DEBUG) printf("OptiXRenderer) creating trimesh_n3f_v3f_hwtri: %d...\n", numfacets);
06787   trimesh_n3f_v3f_cnt += numfacets;
06788 
06789   RTbuffer vbuf, nbuf, cbuf;
06790   RTgeometryinstance instance_hwtri;
06791   RTgeometrytriangles geom_hwtri;
06792 
06793   // Create and fill vertex/normal/color buffers
06794   float3 *vertices; 
06795   uint4 *normals;
06796   uchar4 *colors;
06797   hwtri_alloc_bufs_v3f_n4u4_c4u(ctx, numfacets, vbuf, vertices, nbuf, normals, 
06798                                 cbuf, 1, colors, uniform_color);
06799 
06800   float3 n0, n1, n2;
06801   int i, tcnt;
06802   for (i=0, tcnt=0; i < numfacets; i++) {
06803     int taddr = 3 * tcnt;
06804 
06805     // transform to eye coordinates
06806     wtrans.multpoint3d(v + 9 * i + 0, (float*) &vertices[taddr + 0]);
06807     wtrans.multpoint3d(v + 9 * i + 3, (float*) &vertices[taddr + 1]);
06808     wtrans.multpoint3d(v + 9 * i + 6, (float*) &vertices[taddr + 2]);
06809    
06810     // Compute geometric normal, detect and cull degenerate triangles
06811     float3 Ng;
06812     if (hwtri_test_calc_Ngeom(&vertices[taddr], Ng)) {
06813       continue; // cull any triangle that fails degeneracy tests
06814     }
06815 
06816     wtrans.multnorm3d(n + 9 * i + 0, (float*) &n0.x);
06817     wtrans.multnorm3d(n + 9 * i + 3, (float*) &n1.x);
06818     wtrans.multnorm3d(n + 9 * i + 6, (float*) &n2.x);
06819 
06820     // Pack normals
06821     normals[i].x = packNormal(Ng);
06822     normals[i].y = packNormal(n0);
06823     normals[i].z = packNormal(n1);
06824     normals[i].w = packNormal(n2);
06825 
06826     tcnt++; // count non-culled triangles
06827   }
06828 
06829   rtBufferUnmap(vbuf);
06830   rtBufferUnmap(nbuf);
06831   rtBufferUnmap(cbuf);
06832 
06833   RTERR( rtGeometryTrianglesCreate(ctx, &geom_hwtri) );
06834   RTERR( rtGeometryTrianglesSetPrimitiveCount(geom_hwtri, tcnt) );
06835   RTERR( rtGeometryTrianglesSetVertices(geom_hwtri, tcnt * 3, vbuf, 
06836                                         0, sizeof(float3), RT_FORMAT_FLOAT3) );
06837 #if defined(VMDOPTIXRTXRELEASEBUFS)
06838   RTERR( rtGeometryTrianglesSetBuildFlags(geom_hwtri, RT_GEOMETRY_BUILD_FLAG_RELEASE_BUFFERS) );
06839 #else
06840   append_buffer(vbuf);
06841 #endif
06842 
06843   // create a geometry instance and bind materials to this geometry
06844   RTERR( rtGeometryInstanceCreate(ctx, &instance_hwtri) );
06845   RTERR( rtGeometryInstanceSetGeometryTriangles(instance_hwtri, geom_hwtri) );
06846 
06847   // Enable per-vertex normals, disable per-vertex colors (use uniform color) 
06848   hwtri_set_vertex_flags(ctx, instance_hwtri, nbuf, cbuf, 1, 0);
06849 
06850   // We have to pass the explicit hardware triangle parameter for this geometry
06851   set_material(instance_hwtri, matindex, uniform_color, 1);
06852 
06853   // The vertex buffer is released automatically after construction. 
06854   // We need to keep track of normal and color buffers for ourselves.
06855   append_objects(nbuf, cbuf, geom_hwtri, instance_hwtri);
06856 }
06857 #endif
06858 
06859 
06860 void OptiXRenderer::trimesh_n3f_v3f(Matrix4 & wtrans, 
06861                                     const float *uniform_color, 
06862                                     const float *n, const float *v, 
06863                                     int numfacets, int matindex) {
06864   if (!context_created) return;
06865 
06866 #if defined(ORT_USERTXAPIS)
06867   // OptiX RTX hardware-accelerated triangle API
06868   if (hwtri_enabled) {
06869     trimesh_n3f_v3f_hwtri(wtrans, uniform_color, n, v, numfacets, matindex);
06870     return;
06871   }
06872 #endif
06873 
06874   if (verbose == RT_VERB_DEBUG) printf("OptiXRenderer) creating trimesh_n3f_v3f: %d...\n", numfacets);
06875   trimesh_n3f_v3f_cnt += numfacets;
06876 
06877   int i, ind;
06878   RTbuffer buf;
06879   RTgeometry geom;
06880   RTgeometryinstance instance;
06881   vmd_trimesh_n3f_v3f *trimesh;
06882 
06883   // create and fill the OptiX trimesh memory buffer
06884   rtBufferCreate(ctx, RT_BUFFER_INPUT, &buf);
06885   rtBufferSetFormat(buf, RT_FORMAT_USER);
06886   rtBufferSetElementSize(buf, sizeof(vmd_trimesh_n3f_v3f));
06887   rtBufferSetSize1D(buf, numfacets);
06888   // rtBufferValidate(buf);
06889   rtBufferMap(buf, (void **) &trimesh); // map buffer for writing by host
06890 
06891   for (ind=0,i=0; ind<numfacets; ind++,i+=9) {
06892     // transform to eye coordinates
06893     wtrans.multpoint3d(v + i    , (float*) &trimesh[ind].v0);
06894     wtrans.multpoint3d(v + i + 3, (float*) &trimesh[ind].v1);
06895     wtrans.multpoint3d(v + i + 6, (float*) &trimesh[ind].v2);
06896 
06897     wtrans.multnorm3d(n + i    , (float*) &trimesh[ind].n0);
06898     wtrans.multnorm3d(n + i + 3, (float*) &trimesh[ind].n1);
06899     wtrans.multnorm3d(n + i + 6, (float*) &trimesh[ind].n2);
06900   }
06901   rtBufferUnmap(buf); // triangle list is complete, unmap buffer
06902 
06903   RTERR( rtGeometryCreate(ctx, &geom) );
06904   RTERR( rtGeometrySetPrimitiveCount(geom, numfacets) );
06905   RTERR( rtGeometrySetBoundingBoxProgram(geom, trimesh_n3f_v3f_bbox_pgm) );
06906   RTERR( rtGeometrySetIntersectionProgram(geom, trimesh_n3f_v3f_isct_pgm) );
06907 
06908   // this buffer is associated only with this particular geometry node
06909   RTvariable buf_v;
06910   RTERR( rtGeometryDeclareVariable(geom, "trimesh_n3f_v3f_buffer", &buf_v) );
06911   RTERR( rtVariableSetObject(buf_v, buf) );
06912 
06913   // create a geometry instance and bind materials to this geometry
06914   RTERR( rtGeometryInstanceCreate(ctx, &instance) );
06915   RTERR( rtGeometryInstanceSetGeometry(instance, geom) );
06916 
06917   set_material(instance, matindex, uniform_color);
06918 
06919   append_objects(buf, geom, instance);
06920 }
06921 
06922 
06923 #if defined(ORT_USERTXAPIS)
06924 void OptiXRenderer::trimesh_v3f_hwtri(Matrix4 & wtrans, 
06925                                       const float *uniform_color, 
06926                                       const float *v, 
06927                                       int numfacets, int matindex) {
06928   if (!context_created) return;
06929   if (verbose == RT_VERB_DEBUG) printf("OptiXRenderer) creating trimesh_v3f_hwtri: %d...\n", numfacets);
06930   trimesh_v3f_cnt += numfacets;
06931 
06932   RTbuffer vbuf, nbuf, cbuf;
06933   RTgeometryinstance instance_hwtri;
06934   RTgeometrytriangles geom_hwtri;
06935   
06936   // Create and fill vertex/normal/color buffers
06937   float3 *vertices; 
06938   uint4 *normals;
06939   uchar4 *colors;
06940   hwtri_alloc_bufs_v3f_n4u4_c4u(ctx, numfacets, vbuf, vertices, nbuf, normals, 
06941                                 cbuf, 1, colors, uniform_color);
06942 
06943   int i, tcnt;
06944   for (i=0, tcnt=0; i < numfacets; i++) {
06945     int taddr = 3 * tcnt;
06946 
06947     // transform to eye coordinates
06948     wtrans.multpoint3d(v + 9 * i + 0, (float*) &vertices[taddr + 0]);
06949     wtrans.multpoint3d(v + 9 * i + 3, (float*) &vertices[taddr + 1]);
06950     wtrans.multpoint3d(v + 9 * i + 6, (float*) &vertices[taddr + 2]);
06951 
06952     // Compute geometric normal, detect and cull degenerate triangles
06953     float3 Ng;
06954     if (hwtri_test_calc_Ngeom(&vertices[taddr], Ng)) {
06955       continue; // cull any triangle that fails degeneracy tests
06956     }
06957 
06958     // Pack normal (we don't have per-vertex normals, so leave them empty)
06959     normals[i].x = packNormal(Ng);
06960     // XXX we could initialize the others for paranoia's sake...
06961     // normals[i].y = normals[i].z = normals[i].w = normals[i].x;
06962 
06963     tcnt++; // count non-culled triangles
06964   }
06965 
06966   rtBufferUnmap(vbuf);
06967   rtBufferUnmap(nbuf);
06968   rtBufferUnmap(cbuf);
06969 
06970   RTERR( rtGeometryTrianglesCreate(ctx, &geom_hwtri) );
06971   RTERR( rtGeometryTrianglesSetPrimitiveCount(geom_hwtri, tcnt) );
06972   RTERR( rtGeometryTrianglesSetVertices(geom_hwtri, tcnt * 3, vbuf, 
06973                                         0, sizeof(float3), RT_FORMAT_FLOAT3) );
06974 #if defined(VMDOPTIXRTXRELEASEBUFS)
06975   RTERR( rtGeometryTrianglesSetBuildFlags(geom_hwtri, RT_GEOMETRY_BUILD_FLAG_RELEASE_BUFFERS) );
06976 #else
06977   append_buffer(vbuf);
06978 #endif
06979 
06980   // create a geometry instance and bind materials to this geometry
06981   RTERR( rtGeometryInstanceCreate(ctx, &instance_hwtri) );
06982   RTERR( rtGeometryInstanceSetGeometryTriangles(instance_hwtri, geom_hwtri) );
06983 
06984   // Disable per-vertex normals, disable per-vertex colors (use uniform color) 
06985   hwtri_set_vertex_flags(ctx, instance_hwtri, nbuf, cbuf, 0, 0);
06986 
06987   // We have to pass the explicit hardware triangle parameter for this geometry
06988   set_material(instance_hwtri, matindex, uniform_color, 1);
06989 
06990   // The vertex buffer is released automatically after construction. 
06991   // We need to keep track of normal and color buffers for ourselves.
06992   append_objects(nbuf, cbuf, geom_hwtri, instance_hwtri);
06993 }
06994 #endif
06995 
06996 
06997 void OptiXRenderer::trimesh_v3f(Matrix4 & wtrans, const float *uniform_color, 
06998                                 const float *v, int numfacets, int matindex) {
06999   if (!context_created) return;
07000 
07001 #if defined(ORT_USERTXAPIS)
07002   // OptiX RTX hardware-accelerated triangle API
07003   if (hwtri_enabled) {
07004     trimesh_v3f_hwtri(wtrans, uniform_color, v, numfacets, matindex);
07005     return;
07006   }
07007 #endif
07008 
07009   if (verbose == RT_VERB_DEBUG) printf("OptiXRenderer) creating trimesh_v3f: %d...\n", numfacets);
07010   trimesh_v3f_cnt += numfacets;
07011 
07012   long i, ind;
07013   RTbuffer buf;
07014   RTgeometry geom;
07015   RTgeometryinstance instance;
07016   vmd_trimesh_v3f *trimesh;
07017 
07018   // create and fill the OptiX trimesh memory buffer
07019   rtBufferCreate(ctx, RT_BUFFER_INPUT, &buf);
07020   rtBufferSetFormat(buf, RT_FORMAT_USER);
07021   rtBufferSetElementSize(buf, sizeof(vmd_trimesh_v3f));
07022   rtBufferSetSize1D(buf, numfacets);
07023   // rtBufferValidate(buf);
07024   rtBufferMap(buf, (void **) &trimesh); // map buffer for writing by host
07025 
07026   for (ind=0,i=0; ind<numfacets; ind++,i+=9) {
07027     // transform to eye coordinates
07028     wtrans.multpoint3d(v + i    , (float*) &trimesh[ind].v0);
07029     wtrans.multpoint3d(v + i + 3, (float*) &trimesh[ind].v1);
07030     wtrans.multpoint3d(v + i + 6, (float*) &trimesh[ind].v2);
07031   }
07032   rtBufferUnmap(buf); // triangle list is complete, unmap buffer
07033 
07034   RTERR( rtGeometryCreate(ctx, &geom) );
07035   RTERR( rtGeometrySetPrimitiveCount(geom, numfacets) );
07036   RTERR( rtGeometrySetBoundingBoxProgram(geom, trimesh_v3f_bbox_pgm) );
07037   RTERR( rtGeometrySetIntersectionProgram(geom, trimesh_v3f_isct_pgm) );
07038 
07039   // this buffer is associated only with this particular geometry node
07040   RTvariable buf_v;
07041   RTERR( rtGeometryDeclareVariable(geom, "trimesh_v3f_buffer", &buf_v) );
07042   RTERR( rtVariableSetObject(buf_v, buf) );
07043 
07044   // create a geometry instance and bind materials to this geometry
07045   RTERR( rtGeometryInstanceCreate(ctx, &instance) );
07046   RTERR( rtGeometryInstanceSetGeometry(instance, geom) );
07047 
07048   set_material(instance, matindex, uniform_color);
07049 
07050   append_objects(buf, geom, instance);
07051 }
07052 
07053 
07054 #if defined(ORT_USERTXAPIS)
07055 void OptiXRenderer::tristrip_hwtri(Matrix4 & wtrans, int numverts, 
07056                                    const float * cnv,
07057                                    int numstrips, const int *vertsperstrip,
07058                                    const int *facets, int matindex) {
07059   if (!context_created) return;
07060   int i;
07061   int numfacets = 0;
07062   for (i=0; i<numstrips; i++) 
07063     numfacets += (vertsperstrip[i] - 2);  
07064 
07065   if (verbose == RT_VERB_DEBUG) printf("OptiXRenderer) creating tristrip_hwtri: %d...\n", numfacets);
07066   tricolor_cnt += numfacets;
07067 
07068   RTbuffer vbuf, nbuf, cbuf;
07069   RTgeometryinstance instance_hwtri;
07070   RTgeometrytriangles geom_hwtri;
07071 
07072   // Create and fill vertex/normal/color buffers
07073   float3 *vertices; 
07074   uint4 *normals;
07075   uchar4 *colors;
07076   hwtri_alloc_bufs_v3f_n4u4_c4u(ctx, numfacets, vbuf, vertices, nbuf, normals, 
07077                                 cbuf, numfacets * 3, colors, NULL);
07078 
07079   // render triangle strips one triangle at a time
07080   // triangle winding order is:
07081   //   v0, v1, v2, then v2, v1, v3, then v2, v3, v4, etc.
07082   int strip, t, v = 0;
07083   int stripaddr[2][3] = { {0, 1, 2}, {1, 0, 2} };
07084 
07085   // loop over all of the triangle strips
07086   int tcnt=0; // set triangle index to 0
07087   for (strip=0; strip < numstrips; strip++) {
07088     // loop over all triangles in this triangle strip
07089     for (t = 0; t < (vertsperstrip[strip] - 2); t++) {
07090       int taddr = 3 * tcnt;
07091 
07092       // render one triangle, using lookup table to fix winding order
07093       int v0 = facets[v + (stripaddr[t & 0x01][0])] * 10;
07094       int v1 = facets[v + (stripaddr[t & 0x01][1])] * 10;
07095       int v2 = facets[v + (stripaddr[t & 0x01][2])] * 10;
07096 
07097       // transform to eye coordinates
07098       wtrans.multpoint3d(cnv + v0 + 7, (float*) &vertices[taddr + 0]);
07099       wtrans.multpoint3d(cnv + v1 + 7, (float*) &vertices[taddr + 1]);
07100       wtrans.multpoint3d(cnv + v2 + 7, (float*) &vertices[taddr + 2]);
07101 
07102       // Compute geometric normal, detect and cull degenerate triangles
07103       float3 Ng;
07104       if (hwtri_test_calc_Ngeom(&vertices[taddr], Ng)) {
07105         v++;      // move on to next vertex
07106         continue; // cull any triangle that fails degeneracy tests
07107       }
07108 
07109       float3 n0, n1, n2;
07110       wtrans.multnorm3d(cnv + v0 + 4, (float*) &n0);
07111       wtrans.multnorm3d(cnv + v1 + 4, (float*) &n1);
07112       wtrans.multnorm3d(cnv + v2 + 4, (float*) &n2);
07113 
07114       // Pack normals
07115       normals[tcnt].x = packNormal(Ng);
07116       normals[tcnt].y = packNormal(n0);
07117       normals[tcnt].z = packNormal(n1);
07118       normals[tcnt].w = packNormal(n2);
07119 
07120       // convert color format
07121       colors[taddr + 0].x = cnv[v0 + 0] * 255.0f;
07122       colors[taddr + 0].y = cnv[v0 + 1] * 255.0f;
07123       colors[taddr + 0].z = cnv[v0 + 2] * 255.0f;
07124 
07125       colors[taddr + 1].x = cnv[v1 + 0] * 255.0f;
07126       colors[taddr + 1].y = cnv[v1 + 1] * 255.0f;
07127       colors[taddr + 1].z = cnv[v1 + 2] * 255.0f;
07128 
07129       colors[taddr + 2].x = cnv[v2 + 0] * 255.0f;
07130       colors[taddr + 2].y = cnv[v2 + 1] * 255.0f;
07131       colors[taddr + 2].z = cnv[v2 + 2] * 255.0f;
07132 
07133       v++;    // move on to next vertex
07134       tcnt++; // count non-culled triangles
07135     }
07136     v+=2; // last two vertices are already used by last triangle
07137   }
07138 
07139   rtBufferUnmap(vbuf);
07140   rtBufferUnmap(nbuf);
07141   rtBufferUnmap(cbuf);
07142 
07143   RTERR( rtGeometryTrianglesCreate(ctx, &geom_hwtri) );
07144   RTERR( rtGeometryTrianglesSetPrimitiveCount(geom_hwtri, tcnt) );
07145   RTERR( rtGeometryTrianglesSetVertices(geom_hwtri, tcnt * 3, vbuf, 
07146                                         0, sizeof(float3), RT_FORMAT_FLOAT3) );
07147 #if defined(VMDOPTIXRTXRELEASEBUFS)
07148   RTERR( rtGeometryTrianglesSetBuildFlags(geom_hwtri, RT_GEOMETRY_BUILD_FLAG_RELEASE_BUFFERS) );
07149 #else
07150   append_buffer(vbuf);
07151 #endif
07152 
07153   // create a geometry instance and bind materials to this geometry
07154   RTERR( rtGeometryInstanceCreate(ctx, &instance_hwtri) );
07155   RTERR( rtGeometryInstanceSetGeometryTriangles(instance_hwtri, geom_hwtri) );
07156 
07157   // Enable per-vertex normals, enable per-vertex colors
07158   hwtri_set_vertex_flags(ctx, instance_hwtri, nbuf, cbuf, 1, 1);
07159 
07160   // We have to pass the explicit hardware triangle parameter for this geometry
07161   set_material(instance_hwtri, matindex, NULL, 1);
07162 
07163   // The vertex buffer is released automatically after construction. 
07164   // We need to keep track of normal and color buffers for ourselves.
07165   append_objects(nbuf, cbuf, geom_hwtri, instance_hwtri);
07166 }
07167 #endif
07168 
07169 
07170 void OptiXRenderer::tristrip(Matrix4 & wtrans, int numverts, const float * cnv,
07171                              int numstrips, const int *vertsperstrip,
07172                              const int *facets, int matindex) {
07173   if (!context_created) return;
07174   int i;
07175   int numfacets = 0;
07176   for (i=0; i<numstrips; i++) 
07177     numfacets += (vertsperstrip[i] - 2);  
07178 
07179 #if defined(ORT_USERTXAPIS)
07180   // OptiX RTX hardware-accelerated triangle API
07181   if (hwtri_enabled) {
07182     tristrip_hwtri(wtrans, numverts, cnv, numstrips, 
07183                    vertsperstrip, facets, matindex);
07184     return;
07185   }
07186 #endif
07187 
07188   if (verbose == RT_VERB_DEBUG) printf("OptiXRenderer) creating tristrip: %d...\n", numfacets);
07189   tricolor_cnt += numfacets;
07190 
07191   RTbuffer buf;
07192   RTgeometry geom;
07193   RTgeometryinstance instance;
07194   vmd_tricolor *trimesh;
07195 
07196   // create and fill the OptiX trimesh memory buffer
07197   rtBufferCreate(ctx, RT_BUFFER_INPUT, &buf);
07198   rtBufferSetFormat(buf, RT_FORMAT_USER);
07199   rtBufferSetElementSize(buf, sizeof(vmd_tricolor));
07200   rtBufferSetSize1D(buf, numfacets);
07201   // rtBufferValidate(buf);
07202   rtBufferMap(buf, (void **) &trimesh); // map buffer for writing by host
07203 
07204   // render triangle strips one triangle at a time
07205   // triangle winding order is:
07206   //   v0, v1, v2, then v2, v1, v3, then v2, v3, v4, etc.
07207   int strip, t, v = 0;
07208   int stripaddr[2][3] = { {0, 1, 2}, {1, 0, 2} };
07209 
07210   // loop over all of the triangle strips
07211   i=0; // set triangle index to 0
07212   for (strip=0; strip < numstrips; strip++) {
07213     // loop over all triangles in this triangle strip
07214     for (t = 0; t < (vertsperstrip[strip] - 2); t++) {
07215       // render one triangle, using lookup table to fix winding order
07216       int v0 = facets[v + (stripaddr[t & 0x01][0])] * 10;
07217       int v1 = facets[v + (stripaddr[t & 0x01][1])] * 10;
07218       int v2 = facets[v + (stripaddr[t & 0x01][2])] * 10;
07219 
07220       // transform to eye coordinates
07221       wtrans.multpoint3d(cnv + v0 + 7, (float*) &trimesh[i].v0);
07222       wtrans.multpoint3d(cnv + v1 + 7, (float*) &trimesh[i].v1);
07223       wtrans.multpoint3d(cnv + v2 + 7, (float*) &trimesh[i].v2);
07224 
07225       wtrans.multnorm3d(cnv + v0 + 4, (float*) &trimesh[i].n0);
07226       wtrans.multnorm3d(cnv + v1 + 4, (float*) &trimesh[i].n1);
07227       wtrans.multnorm3d(cnv + v2 + 4, (float*) &trimesh[i].n2);
07228 
07229       vec_copy((float*) &trimesh[i].c0, cnv + v0);
07230       vec_copy((float*) &trimesh[i].c1, cnv + v1);
07231       vec_copy((float*) &trimesh[i].c2, cnv + v2);
07232 
07233       v++; // move on to next vertex
07234       i++; // next triangle
07235     }
07236     v+=2; // last two vertices are already used by last triangle
07237   }
07238   rtBufferUnmap(buf); // triangle list is complete, unmap buffer
07239 
07240   RTERR( rtGeometryCreate(ctx, &geom) );
07241   RTERR( rtGeometrySetPrimitiveCount(geom, numfacets) );
07242   RTERR( rtGeometrySetBoundingBoxProgram(geom, tricolor_bbox_pgm) );
07243   RTERR( rtGeometrySetIntersectionProgram(geom, tricolor_isct_pgm) );
07244 
07245   // this buffer is associated only with this particular geometry node
07246   RTvariable buf_v;
07247   RTERR( rtGeometryDeclareVariable(geom, "tricolor_buffer", &buf_v) );
07248   RTERR( rtVariableSetObject(buf_v, buf) );
07249 
07250   // create a geometry instance and bind materials to this geometry
07251   RTERR( rtGeometryInstanceCreate(ctx, &instance) );
07252   RTERR( rtGeometryInstanceSetGeometry(instance, geom) );
07253 
07254   set_material(instance, matindex, NULL);
07255 
07256   append_objects(buf, geom, instance);
07257 }
07258 
07259 
07260 #if !defined(VMDOPENGL)
07261 // A hack to prevent VMD from having to be linked to libGL.so to resolve
07262 // OptiX dependencies for OpenGL interop, e.g. when compiling on
07263 // a supercomputer/cluster lacking OpenGL support (e.g. ORNL Titan):
07264 //
07265 // Linking  vmd_LINUXAMD64 ...
07266 // /usr/lib64/libGL.so.1: undefined reference to `xcb_glx_set_client_info_arb'
07267 // /usr/lib64/libGL.so.1: undefined reference to `xcb_glx_create_context_attribs_arb_checked'
07268 // /usr/lib64/libGL.so.1: undefined reference to `xcb_glx_set_client_info_2arb'
07269 // /usr/bin/ld: link errors found, deleting executable `vmd_LINUXAMD64'
07270 // collect2: error: ld returned 1 exit status
07271 // make: *** [vmd_LINUXAMD64] Error 1
07272 //
07273 extern "C" {
07274   typedef struct {
07275      unsigned int sequence;
07276   } xcb_void_cookie_t;
07277   static xcb_void_cookie_t fake_cookie = { 0 };
07278   xcb_void_cookie_t xcb_glx_set_client_info_arb(void) {
07279    return fake_cookie;
07280   }
07281   xcb_void_cookie_t xcb_glx_create_context_attribs_arb_checked(void) {
07282    return fake_cookie;
07283   }
07284   xcb_void_cookie_t xcb_glx_set_client_info_2arb(void) {
07285    return fake_cookie;
07286   }
07287 }
07288 #endif
07289 
07290 
07291 

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