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

ANARIRenderer.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: ANARIRenderer.C,v $
00013 *      $Author: johns $      $Locker:  $               $State: Exp $
00014 *      $Revision: 1.26 $         $Date: 2021/12/18 07:27:39 $
00015 *
00016 ***************************************************************************/
00037 #define VMDANARIREPGROUPING 1
00038 
00039 #include <math.h>
00040 #include <stdlib.h>
00041 #include <stdio.h>
00042 #include <string.h>
00043 
00044 #if defined(__linux)
00045 #include <unistd.h>   // needed for symlink() in movie recorder
00046 #endif
00047 
00048 #include "Inform.h"
00049 #include "ImageIO.h"
00050 #include "ANARIRenderer.h"
00051 #include "Matrix4.h"
00052 #include "utilities.h"
00053 #include "WKFUtils.h"
00054 
00055 // #if !(ANARI_VERSION_MAJOR >= 1 && ANARI_VERSION_MINOR >= 2)
00056 // #error VMD requires ANARI >= 1.2.0 for correct transparent AO shading
00057 // // VMD requires ANARI >= 1.1.2 for correct rendering of cylinders
00058 // #endif
00059 
00060 // enable the interactive ray tracing capability
00061 #if defined(VMDANARI_INTERACTIVE_OPENGL)
00062 #if (defined(WIN32) || defined(_WIN64)) && defined(_MSC_VER)
00063 #include <windows.h> // must include windows.h prior to GL
00064 #endif
00065 
00066 #include <GL/gl.h>
00067 #endif
00068 
00069 #if 0
00070 #define DBG() 
00071 #else
00072 #define DBG() printf("ANARIRenderer) ++ %s\n", __func__);
00073 #endif
00074 
00075 #include <algorithm>
00076 
00077 static void vmd_anari_status_callback(void *userData, 
00078                                       ANARIDevice dev,
00079                                       ANARIObject src,
00080                                       ANARIDataType srctype,
00081                                       ANARIStatusSeverity sev,
00082                                       ANARIStatusCode code,
00083                                       const char *message) {
00084   switch (sev) {
00085     case ANARI_SEVERITY_FATAL_ERROR:
00086       printf("ANARIRenderer) FATAL: %s\n", message);
00087       break;
00088 
00089     case ANARI_SEVERITY_ERROR:
00090       printf("ANARIRenderer) ERROR: %s\n", message);
00091       break;
00092 
00093     case ANARI_SEVERITY_WARNING:
00094       printf("ANARIRenderer) WARN: %s\n", message);
00095       break;
00096 
00097     case ANARI_SEVERITY_PERFORMANCE_WARNING:
00098       printf("ANARIRenderer) PERF: %s\n", message);
00099       break;
00100 
00101     case ANARI_SEVERITY_INFO:
00102       printf("ANARIRenderer) INFO: %s\n", message);
00103       break;
00104 
00105     default:
00106       printf("ANARIRenderer) STATUS: %s\n", message);
00107       break;
00108   }
00109 }
00110 
00111 
00112 // Global ANARI initialization routine -- call it only ONCE...
00113 void ANARIRender::ANARI_Global_Init(void) {
00114 //  DBG();
00115 }
00116 
00117 
00118 // Global ANARI initialization routine -- call it only ONCE...
00119 void ANARIRender::ANARI_Global_Shutdown(void) {
00120 }
00121 
00123 #if defined(VMDOPENGL)
00124 extern "C" { 
00125 typedef void ( *__GLXextFuncPtr)(void);
00126 __GLXextFuncPtr glXGetProcAddress (const GLubyte *procName);
00127 }
00128 #endif
00129 
00131 ANARIRender::ANARIRender(void) {
00132   DBG();
00133 
00134   anr_timer = wkf_timer_create(); // create and initialize timer
00135   wkf_timer_start(anr_timer);
00136 
00137   dev = NULL;
00138   rendererworkarounds = ANARI_NONE;
00139   memset(lastcommentstring, 0, sizeof(lastcommentstring));
00140   seqgrp = 0;
00141 
00142   // set ANARI state handles/variables to NULL
00143   anariRenderer = NULL;
00144   anariFrameBuffer = NULL;
00145   anariCamera = NULL;
00146   anariWorld = NULL;
00147   anariLightData = NULL;
00148 
00149   // zero out last rep counters
00150   lastrepmesh=0;
00151   lastrepspheres=0;
00152   lastrepcyls=0;
00153 
00154   lasterror = 0;               // begin with no error state set
00155   context_created = 0;         // no context yet
00156   buffers_allocated = 0;       // flag no buffer allocated yet
00157   scene_created = 0;           // scene has been created
00158 
00159   // clear timers
00160   time_ctx_create = 0.0;
00161   time_ctx_setup = 0.0;
00162   time_ctx_validate = 0.0;
00163   time_ctx_AS_build = 0.0;
00164   time_ray_tracing = 0.0;
00165   time_image_io = 0.0;
00166 
00167   // set default scene background state
00168   scene_background_mode = RT_BACKGROUND_TEXTURE_SOLID;
00169   memset(scene_bg_color, 0, sizeof(scene_bg_color));
00170   memset(scene_bg_grad_top, 0, sizeof(scene_bg_grad_top));
00171   memset(scene_bg_grad_bot, 0, sizeof(scene_bg_grad_bot));
00172   memset(scene_gradient, 0, sizeof(scene_gradient));
00173   scene_gradient_topval = 1.0f;
00174   scene_gradient_botval = 0.0f;
00175   // XXX this has to be recomputed prior to rendering..
00176   scene_gradient_invrange = 1.0f / (scene_gradient_topval - scene_gradient_botval);
00177 
00178   cam_zoom = 1.0f;
00179   cam_stereo_eyesep = 0.06f;
00180   cam_stereo_convergence_dist = 2.0f;
00181 
00182   headlight_enabled = 0;     // VR HMD headlight disabled by default
00183 
00184   shadows_enabled = RT_SHADOWS_OFF; // disable shadows by default 
00185   aa_samples = 0;            // no AA samples by default
00186 
00187   ao_samples = 0;            // no AO samples by default
00188   ao_direct = 0.3f;          // AO direct contribution is 30%
00189   ao_ambient = 0.7f;         // AO ambient contribution is 70%
00190 
00191   dof_enabled = 0;           // disable DoF by default
00192   cam_dof_focal_dist = 2.0f;
00193   cam_dof_fnumber = 64.0f;
00194 
00195   fog_mode = RT_FOG_NONE;    // fog/cueing disabled by default
00196   fog_start = 0.0f;
00197   fog_end = 10.0f;
00198   fog_density = 0.32f;
00199 
00200   rendererworkarounds = ANARI_NONE;
00201   anari_rendermode = ANARI_PATHTRACER;
00202   anari_matclass = ANARI_MATTE;
00203 
00204 // XXX debugging attach delay
00205 printf("debugging PID: %d\n", getpid());
00206 if (getenv("VMDANARISLEEP")) {
00207   int sleepsecs = atoi(getenv("VMDANARISLEEP"));
00208   sleep(sleepsecs);
00209 }
00210 
00211 
00212   if (getenv("VMDANARIUSD"))  {
00213     printf("ANARIRenderer) Attempting to load library: 'usd'\n");
00214     lib = anariLoadLibrary("usd", vmd_anari_status_callback, NULL);
00215     dev = anariNewDevice(lib, "usd");
00216 
00217     if (!dev) {
00218       printf("ANARIRenderer: failed to load USD ANARI library! Exiting!\n");
00219       exit(-1);
00220     }
00221 
00222     int usdConnLogVerbosity = 0;
00223     anariSetParameter(dev, dev, "usd::connection.logverbosity", ANARI_INT32, &usdConnLogVerbosity);
00224 
00225     int usdOutputOmniverse = (getenv("VMDUSEOMNIVERSE") != NULL);
00226     if (usdOutputOmniverse) {
00227       if (!getenv("VMDOMNIVERSEHOST")) {
00228         anariSetParameter(dev, dev, "usd::serialize.hostname", ANARI_STRING, "localhost");
00229       } else { 
00230         anariSetParameter(dev, dev, "usd::serialize.hostname", ANARI_STRING, getenv("VMDOMNIVERSEHOST"));
00231      }
00232     }
00233 
00234     if (!getenv("VMDUSDOUTPUTPATH")) {
00235       anariSetParameter(dev, dev, "usd::serialize.outputpath", ANARI_STRING, "vmdanariusd");
00236     } else {
00237       anariSetParameter(dev, dev, "usd::serialize.outputpath", ANARI_STRING, getenv("VMDUSDOUTPUTPATH"));
00238     }
00239 
00240     int usdOutputBinary = (getenv("VMDANARIUSDASCII") != NULL);
00241     anariSetParameter(dev, dev, "usd::serialize.outputbinary", ANARI_BOOL, &usdOutputBinary);
00242 
00243     anariCommit(dev, dev);
00244 
00245     rendererworkarounds = ANARI_USD;
00246   }
00247 
00248 
00249   // catch-all that reverts to the ref device if we do no better
00250   if (!dev) {
00251     const char *userdev = getenv("VMDANARIDEVICE");
00252     if (userdev) {
00253       printf("ANARIRenderer) attempting to load ANARI device '%s'\n", userdev); 
00254       lib = anariLoadLibrary(userdev, vmd_anari_status_callback, NULL);
00255 
00256     } else {
00257       printf("ANARIRenderer) No library loaded, trying 'example'\n"); 
00258       lib = anariLoadLibrary("example", vmd_anari_status_callback, NULL);
00259     }
00260 
00261     // query available subtypes for this device
00262     const char **devices = anariGetDeviceSubtypes(lib);
00263     if (!devices) {
00264       printf("ANARIRenderer) No device subtypes returned.\n");
00265     } else {
00266       printf("ANARIRenderer) Available devices:\n");
00267       for (const char **d = devices; *d != NULL; d++)
00268         printf("ANARIRenderer)   %s\n", *d);
00269     }
00270 
00271     // query available renderers
00272     int havepathtracer = 0;
00273     const char **renderers = anariGetObjectSubtypes(lib, "default", ANARI_RENDERER);
00274     if (renderers) {
00275       printf("ANARIRenderer) Available renderers:\n");
00276       for (const char **r = renderers; *r != NULL; r++) {
00277         printf("ANARIRenderer)   %s\n", *r);
00278         if (strcmp(*r, "pathtracer") == 0)
00279           havepathtracer = 1;
00280       }
00281     } else {
00282       printf("ANARIRenderer) No renderers available!\n");
00283     }
00284 
00285     const char *rendererstr = "default";
00286     if (havepathtracer)
00287       rendererstr = "pathtracer"; 
00288 
00289     // inspect pathtracer renderer parameters
00290     const ANARIParameter *rendparams = anariGetObjectParameters(lib, "default", "pathtracer", ANARI_RENDERER);
00291 
00292     if (!rendparams) {
00293       printf("ANARIRenderer) Renderer '%s' has no parameters.\n", rendererstr);
00294     } else {
00295       printf("ANARIRenderer) Parameters of '%s':\n", rendererstr);
00296       for (const ANARIParameter *p = rendparams; p->name != NULL; p++) {
00297         const char *desc = (const char *) anariGetParameterInfo(lib,
00298             "default",
00299             "pathtracer",
00300             ANARI_RENDERER,
00301             p->name,
00302             p->type,
00303             "description",
00304             ANARI_STRING);
00305 
00306         const int *required = (const int *) anariGetParameterInfo(lib,
00307             "default",
00308             "pathtracer",
00309             ANARI_RENDERER,
00310             p->name,
00311             p->type,
00312             "required",
00313             ANARI_BOOL);
00314 
00315         printf("ANARIRenderer)   [%d] %s, %s: %s\n",
00316                int(p->type), p->name, required && *required ? "REQ" : "OPT", desc);
00317       }
00318     }
00319 
00320     dev = anariNewDevice(lib, "default");
00321 
00322     if (!dev) {
00323       printf("ANARIRenderer: failed to load ANARI library! Exiting!\n");
00324       exit(-1);
00325     }
00326 
00327     anariCommit(dev, dev);
00328 
00329     rendererworkarounds = ANARI_NONE;
00330     anari_rendermode = ANARI_PATHTRACER;
00331   }
00332 
00333 
00334   if (getenv("VMDANARITRACE")) {
00335     // Trace output will be written to filename specified by env variable:
00336     //   ANARI_DEBUG_TRACE  
00337     anariLoadLibrary("debug", vmd_anari_status_callback, NULL); // enable ANARI API tracing
00338   }
00339 
00340 
00341 
00342 #if 0
00343 #if 1
00344   if (getenv("VMDANARITRACE")) {
00345     // Trace output will be written to filename specified by env variable:
00346     //   ANARI_DEBUG_TRACE  
00347     lib = anariLoadLibrary("debug", vmd_anari_status_callback, NULL); // enable ANARI API tracing
00348   }
00349 
00350   if (getenv("VMDANARINVGL"))  {
00351     printf("ANARIRenderer) Attempting to load library: 'nvgl'\n");
00352     lib = anariLoadLibrary("nvgl", vmd_anari_status_callback, NULL);
00353     dev = anariNewDevice(lib, "nvgl");
00354     rendererworkarounds = ANARI_NVGL;
00355 #if defined(VMDOPENGL)
00356     const void *ptr = (const void*) glXGetProcAddress;
00357     anariSetParameter(dev, dev, "oglGetProcAddress", ANARI_VOID_PTR, &ptr);
00358 #endif
00359   } else if (getenv("VMDANARIUSD"))  {
00360     printf("ANARIRenderer) Attempting to load library: 'usd'\n");
00361     lib = anariLoadLibrary("usd", vmd_anari_status_callback, NULL);
00362     dev = anariNewDevice(lib, "usd");
00363     anariSetParameter(dev, dev, "serialize.location", ANARI_STRING, "/tmp/foobar");
00364     rendererworkarounds = ANARI_USD;
00365   } else if (getenv("VMDANARIOSPRAY"))  {
00366     printf("ANARIRenderer) Attempting to load library: 'ospray'\n");
00367     lib = anariLoadLibrary("ospray", vmd_anari_status_callback, NULL);
00368     dev = anariNewDevice(lib, "ospray");
00369     rendererworkarounds = ANARI_OSPRAY;
00370   }
00371 #endif
00372 
00373   if (!dev) {
00374     printf("ANARIRenderer) No devices loaded, trying 'example'\n"); 
00375     lib = anariLoadLibrary("example", vmd_anari_status_callback, NULL);
00376     dev = anariNewDevice(lib, "example");
00377   }
00378 
00379   if (getenv("VMDANARIOWL") == NULL) {
00380     int loglevel = ANARI_LOG_INFO;
00381     loglevel = ANARI_LOG_DEBUG;
00382     printf("ANARIRenderer) setting device log level property...\n");
00383     anariSetParameter(dev, dev, "logLevel", ANARI_INT32, &loglevel);
00384   }
00385   anariCommit(dev, dev);
00386 
00387   printf("ANARIRenderer) setting renderer mode\n");
00388   anari_rendermode = ANARI_PATHTRACER;
00389   if (getenv("VMDANARISCIVIS")) {
00390     printf("ANARIRenderer) Renderer mode set to 'scivis'\n");
00391     anari_rendermode = ANARI_SCIVIS;
00392   }
00393   if (getenv("VMDANARIPATHTRACER")) {
00394     printf("ANARIRenderer) Renderer mode set to 'pathtracer'\n");
00395     anari_rendermode = ANARI_PATHTRACER;
00396   }
00397 #endif
00398 
00399 
00400 
00401   // verbose = RT_VERB_MIN;    // quiet console except for perf/debugging cases
00402   verbose = RT_VERB_DEBUG;  // extensive console output
00403   check_verbose_env();      // see if the user has overridden verbose flag
00404 
00405   printf("ANARIRenderer) clear/init scene data structures\n");
00406   destroy_scene();          // clear/init geometry vectors
00407   anariInstances.clear();   // clear instance list
00408 
00409   init_materials();
00410 
00411   directional_lights.clear();
00412   positional_lights.clear();
00413 
00414   // clear all primitive lists
00415   trimesh_v3f_n3f_c3f.clear();
00416   spheres_color.clear();
00417   cylinders_color.clear();
00418   surfbufs.clear();
00419 
00420   double starttime = wkf_timer_timenow(anr_timer);
00421 
00422   if (verbose == RT_VERB_DEBUG) printf("ANARIRenderer) creating context...\n");
00423 
00424   //
00425   // create the main renderer object needed early on for 
00426   // instantiation of materials, lights, etc.
00427   // 
00428   const char *rstr;
00429   switch (anari_rendermode) {
00430     case ANARI_PATHTRACER: rstr = "pathtracer";        break;
00431     case ANARI_DEFAULT:    rstr = "default";           break;
00432     case ANARI_SCIVIS:     rstr = "scivis";            break;
00433     case ANARI_AO:         rstr = "ambientocclusion";  break;
00434               default:     rstr = "default";           break;
00435   }
00436 
00437   if (rendererworkarounds == ANARI_NVGL) {
00438     rstr = "default";
00439     anari_rendermode = ANARI_DEFAULT;
00440     printf("ANARIRenderer) INFO: NVGL back-end requires default renderer\n");
00441   }
00442 
00443   if ((anariRenderer = anariNewRenderer(dev, rstr)) == NULL) {
00444     printf("ANARIRenderer) Failed to load renderer '%s'!\n", rstr);
00445   }
00446   if (verbose == RT_VERB_TIMING || verbose == RT_VERB_DEBUG) {
00447     printf("ANARIRenderer) created renderer '%s'\n", rstr);
00448   }
00449 
00450   time_ctx_create = wkf_timer_timenow(anr_timer) - starttime;
00451   
00452   if (verbose == RT_VERB_TIMING || verbose == RT_VERB_DEBUG) {
00453     printf("ANARIRenderer) context creation time: %.2f\n", time_ctx_create);
00454   }
00455 
00456   context_created = 1;
00457 }
00458 
00459         
00461 ANARIRender::~ANARIRender(void) {
00462   DBG();
00463 
00464   destroy_scene();
00465 
00466   if (context_created && (anariRenderer != NULL))
00467     anariRelease(dev, anariRenderer);
00468 
00469   anariRenderer=NULL;
00470   context_created=0;
00471 
00472   if (dev != NULL)
00473     anariRelease(dev, dev);
00474   dev=NULL;
00475 
00476   // how do we free a library? or do we?
00477   lib=NULL;
00478 
00479   materialcache.clear();
00480 
00481   directional_lights.clear();
00482   positional_lights.clear();
00483 
00484   wkf_timer_destroy(anr_timer);
00485 }
00486 
00487 
00488 void ANARIRender::check_verbose_env() {
00489   DBG();
00490 
00491   char *verbstr = getenv("VMDANARIVERBOSE");
00492   if (verbstr != NULL) {
00493 //    printf("ANARIRenderer) verbosity config request: '%s'\n", verbstr);
00494     if (!strupcmp(verbstr, "MIN")) {
00495       verbose = RT_VERB_MIN;
00496       printf("ANARIRenderer) verbose setting: minimum\n");
00497     } else if (!strupcmp(verbstr, "TIMING")) {
00498       verbose = RT_VERB_TIMING;
00499       printf("ANARIRenderer) verbose setting: timing data\n");
00500     } else if (!strupcmp(verbstr, "DEBUG")) {
00501       verbose = RT_VERB_DEBUG;
00502       printf("ANARIRenderer) verbose setting: full debugging data\n");
00503     }
00504   }
00505 }
00506 
00507 
00508 void ANARIRender::setup_context(int w, int h) {
00509   DBG();
00510   double starttime = wkf_timer_timenow(anr_timer);
00511   time_ctx_setup = 0;
00512 
00513   lasterror = 0; /* XXX SUCCESS; */ // clear any error state
00514   width = w;
00515   height = h;
00516 
00517   if (!context_created)
00518     return;
00519 
00520   check_verbose_env(); // update verbose flag if changed since last run
00521 
00522   // maxPathLength -- supported by all renderers
00523   if (getenv("VMDANARIMAXDEPTH")) {
00524     int maxdepth = atoi(getenv("VMDANARIMAXDEPTH"));
00525     if (maxdepth > 0 && maxdepth <= 20) {
00526       printf("ANARIRenderer) Setting maxdepth to %d...\n", maxdepth);
00527       anariSetParameter(dev, anariRenderer, "maxPathLength", ANARI_INT32, &maxdepth);  
00528     } else {
00529       printf("ANARIRenderer) ignoring out-of-range maxdepth: %d...\n", maxdepth);
00530     }
00531   } else {
00532     int maxdepth = 20;
00533     anariSetParameter(dev, anariRenderer, "maxPathLength", ANARI_INT32, &maxdepth);  
00534   }
00535  
00536 #if 0
00537   // XXX -- not implemented in ANARI 2.x presently
00538   // Implore ANARI to correctly handle lighting through transparent 
00539   // surfaces when AO is enabled
00540   const int one = 1;
00541   anariSetParameter(dev, anariRenderer, "aoTransparencyEnabled", ANARI_INT32, &one);
00542 #endif
00543 
00544   time_ctx_setup = wkf_timer_timenow(anr_timer) - starttime;
00545 }
00546 
00547 
00548 void ANARIRender::destroy_scene() {
00549   DBG();
00550 
00551   double starttime = wkf_timer_timenow(anr_timer);
00552   time_ctx_destroy_scene = 0;
00553 
00554   // zero out all object counters
00555   cylinder_array_cnt = 0;
00556   cylinder_array_color_cnt = 0;
00557   ring_array_color_cnt = 0;
00558   sphere_array_cnt = 0;
00559   sphere_array_color_cnt = 0;
00560   tricolor_cnt = 0;
00561   trimesh_c4u_n3b_v3f_cnt = 0;
00562   trimesh_n3b_v3f_cnt = 0;
00563   trimesh_n3f_v3f_cnt = 0;
00564   trimesh_v3f_cnt = 0;
00565 
00566   // zero out last rep counters
00567   lastrepmesh=0;
00568   lastrepspheres=0;
00569   lastrepcyls=0;
00570 
00571   // frame depends on lots of other objects,
00572   // so we destroy it early
00573   framebuffer_destroy();
00574 
00575   // clear lists of primitives
00576   int i;
00577   for (i=0; i<trimesh_v3f_n3f_c3f.num(); i++) {
00578     free(trimesh_v3f_n3f_c3f[i].v);
00579     trimesh_v3f_n3f_c3f[i].v = NULL;
00580     free(trimesh_v3f_n3f_c3f[i].n);
00581     trimesh_v3f_n3f_c3f[i].n = NULL;
00582     free(trimesh_v3f_n3f_c3f[i].c);
00583     trimesh_v3f_n3f_c3f[i].c = NULL;
00584     free(trimesh_v3f_n3f_c3f[i].f);
00585     trimesh_v3f_n3f_c3f[i].f = NULL;
00586   }
00587   trimesh_v3f_n3f_c3f.clear();
00588 
00589   for (i=0; i<spheres_color.num(); i++) {
00590     free(spheres_color[i].xyz);
00591     spheres_color[i].xyz = NULL;
00592     free(spheres_color[i].radii);
00593     spheres_color[i].radii = NULL;
00594     free(spheres_color[i].colors);
00595     spheres_color[i].colors = NULL;
00596   }
00597   spheres_color.clear();
00598 
00599   for (i=0; i<cylinders_color.num(); i++) {
00600     free(cylinders_color[i].cyls);
00601     cylinders_color[i].cyls = NULL;
00602     free(cylinders_color[i].rads);
00603     cylinders_color[i].rads = NULL;
00604     free(cylinders_color[i].ind);
00605     cylinders_color[i].ind = NULL;
00606     free(cylinders_color[i].cols);
00607     cylinders_color[i].cols = NULL;
00608   }
00609   cylinders_color.clear();
00610 
00611   for (i=0; i<surfbufs.num(); i++) {
00612     free(surfbufs[i]);
00613     surfbufs[i] = NULL;
00614   }
00615   surfbufs.clear();
00616 
00617   anariInstances.clear();
00618 
00619   for (i=0; i<materialcache.num(); i++) {
00620     if (materialcache[i].isvalid)
00621       anariRelease(dev, materialcache[i].mat);
00622   }
00623   materialcache.clear();
00624 
00625   int lcnt = anariLights.num();
00626   for (i = 0; i < lcnt; ++i) {
00627     anariRelease(dev, anariLights[i]);
00628   }
00629   anariLights.clear();
00630 
00631 
00632   if (anariCamera != NULL) {
00633     anariRelease(dev, anariCamera);
00634     anariCamera = NULL;
00635   }
00636 
00637   if (anariWorld != NULL) {
00638     anariRelease(dev, anariWorld);
00639     anariWorld = NULL;
00640   }
00641 
00642 
00643   double endtime = wkf_timer_timenow(anr_timer);
00644   time_ctx_destroy_scene = endtime - starttime;
00645 
00646   scene_created = 0; // scene has been destroyed
00647 }
00648 
00649 
00650 void ANARIRender::update_rendering_state(int interactive) {
00651   DBG();
00652   if (!context_created)
00653     return;
00654 
00655   wkf_timer_start(anr_timer);
00656 
00657   // Set interactive/progressive rendering flag so that we wire up
00658   // the most appropriate renderer for the task.  For batch rendering
00659   // with AO, we would choose the largest possible sample batch size,
00660   // but for interactive we will always choose a batch size of 1 or maybe 2
00661   // to yield the best interactivity.
00662   interactive_renderer = interactive;
00663 
00664   // XXX set ANARI rendering state
00665 
00666   long totaltris = tricolor_cnt + trimesh_c4u_n3b_v3f_cnt + 
00667                    trimesh_n3b_v3f_cnt + trimesh_n3f_v3f_cnt + trimesh_v3f_cnt;
00668 
00669   if (verbose == RT_VERB_TIMING || verbose == RT_VERB_DEBUG) {
00670     printf("ANARIRenderer) cyl %ld, ring %ld, sph %ld, tri %ld, tot: %ld  lt %ld\n",
00671            cylinder_array_cnt + cylinder_array_color_cnt,
00672            ring_array_color_cnt,
00673            sphere_array_cnt + sphere_array_color_cnt,
00674            totaltris,
00675            cylinder_array_cnt +  cylinder_array_color_cnt + ring_array_color_cnt + sphere_array_cnt + sphere_array_color_cnt + totaltris,
00676            directional_lights.num() + positional_lights.num());
00677   }
00678 
00679   if (verbose == RT_VERB_DEBUG) {
00680     printf("ANARIRenderer) using fully general shader and materials.\n");
00681   }
00682 
00683   // XXX set ANARI background color
00684 
00685   if (verbose == RT_VERB_DEBUG) {
00686     printf("ANARIRenderer) scene bg mode: %d\n", scene_background_mode);
00687 
00688     printf("ANARIRenderer) scene bgsolid: %.2f %.2f %.2f\n", 
00689            scene_bg_color[0], scene_bg_color[1], scene_bg_color[2]);
00690 
00691     printf("ANARIRenderer) scene bggradT: %.2f %.2f %.2f\n", 
00692            scene_bg_grad_top[0], scene_bg_grad_top[1], scene_bg_grad_top[2]);
00693 
00694     printf("ANARIRenderer) scene bggradB: %.2f %.2f %.2f\n", 
00695            scene_bg_grad_bot[0], scene_bg_grad_bot[1], scene_bg_grad_bot[2]);
00696   
00697     printf("ANARIRenderer) bg gradient: %f %f %f  top: %f  bot: %f\n",
00698            scene_gradient[0], scene_gradient[1], scene_gradient[2],
00699            scene_gradient_topval, scene_gradient_botval);
00700   }
00701 
00702   // update in case the caller changed top/bottom values since last recalc
00703   scene_gradient_invrange = 1.0f / (scene_gradient_topval - scene_gradient_botval);
00704   // XXX set ANARI background gradient
00705 
00706   // XXX set ANARI fog mode
00707 
00708   if (verbose == RT_VERB_DEBUG) {
00709     printf("ANARIRenderer) adding lights: dir: %ld  pos: %ld\n", 
00710            directional_lights.num(), positional_lights.num());
00711   }
00712 
00713   // XXX set ANARI lights
00714 
00715   if (verbose == RT_VERB_DEBUG) 
00716     printf("ANARIRenderer) Finalizing ANARI scene graph...\n");
00717 
00718   // create group to hold instances
00719 
00720   // XXX we should create an acceleration object the instance shared
00721   //     by multiple PBC images
00722 
00723 
00724   // XXX ANARI AS builder initialization if there's any customization...
00725 
00726   // do final state variable updates before rendering begins
00727   if (verbose == RT_VERB_DEBUG) {
00728     printf("ANARIRenderer) cam zoom factor %f\n", cam_zoom);
00729     printf("ANARIRenderer) cam stereo eye separation  %f\n", cam_stereo_eyesep);
00730     printf("ANARIRenderer) cam stereo convergence distance %f\n", 
00731            cam_stereo_convergence_dist);
00732     printf("ANARIRenderer) cam DoF focal distance %f\n", cam_dof_focal_dist);
00733     printf("ANARIRenderer) cam DoF f/stop %f\n", cam_dof_fnumber);
00734   }
00735 
00736   // define all of the standard camera params
00737   // XXX set ANARI camera state
00738 
00739   // define stereoscopic camera parameters
00740   // XXX set ANARI camera state
00741 
00742   // define camera DoF parameters
00743   // XXX set ANARI camera state
00744 
00745   // XXX set ANARI AO sample counts and light scaling factors
00746 
00747   if (verbose == RT_VERB_DEBUG) {
00748     printf("ANARIRenderer) setting sample counts:  AA %d  AO %d\n", aa_samples, ao_samples);
00749     printf("ANARIRenderer) setting AO factors:  AOA %f  AOD %f\n", ao_ambient, ao_direct);
00750   }
00751 
00752   //
00753   // Handle AA samples either internally with loops internal to 
00754   // each ray launch point thread, or externally by iterating over
00755   // multiple launches, adding each sample to an accumulation buffer,
00756   // or a hybrid combination of the two.  
00757   //
00758 #if 1
00759   ext_aa_loops = std::max(aa_samples, 1) * std::max(ao_samples, 1);
00760 #else
00761   ext_aa_loops = 1;
00762   if (ao_samples > 0 || (aa_samples > 4)) {
00763     // if we have too much work for a single-pass rendering, we need to 
00764     // break it up into multiple passes of the right counts in each pass
00765     ext_aa_loops = 1 + aa_samples;
00766     // XXX set ANARI sample counts per launch...
00767   } else { 
00768     // if the scene is simple, e.g. no AO rays and AA sample count is small,
00769     // we can run it in a single pass and get better performance
00770     // XXX set ANARI sample counts per launch...
00771   }
00772   // XXX set ANARI accum buf normalization scaling factors
00773 #endif
00774 
00775   if (verbose == RT_VERB_DEBUG) {
00776     if (ext_aa_loops > 1)
00777       printf("ANARIRenderer) Running ANARI multi-pass: %d loops\n", ext_aa_loops);
00778     else
00779       printf("ANARIRenderer) Running ANARI single-pass: %d total samples\n", 1+aa_samples);
00780   }
00781 
00782   // set the ray generation program to the active camera code...
00783   // XXX set ANARI camera mode and clear accum buf
00784   // set the active color accumulation ray gen program based on the 
00785   // camera/projection mode, stereoscopic display mode, 
00786   // and depth-of-field state
00787   // XXX set ANARI camera mode and accum buf mode
00788   // XXX set ANARI "miss" shading mode (solid or gradient)
00789 }
00790 
00791 
00792 void ANARIRender::framebuffer_config(int fbwidth, int fbheight) {
00793   DBG();
00794   if (!context_created)
00795     return;
00796 
00797   width = fbwidth;
00798   height = fbheight;
00799 
00800   // allocate and resize buffers to match request
00801   if (buffers_allocated) {
00802     // if the buffers already exist and match the current 
00803     // progressive/non-progressive rendering mode, just resize them
00804     if (verbose == RT_VERB_DEBUG) {
00805       printf("ANARIRenderer) resizing framebuffer\n");
00806     }
00807     framebuffer_resize(width, height);
00808   } else {
00809     // (re)allocate framebuffer and associated accumulation buffers if they
00810     // don't already exist or if they weren't bound properly for
00811     // current progressive/non-progressive rendering needs.
00812     if (verbose == RT_VERB_DEBUG) {
00813       printf("ANARIRenderer) creating framebuffer and accum. buffer\n");
00814     }
00815 
00816     // XXX for ANARI framebuffer setup is completely deferred to render-time
00817 
00818     buffers_allocated = 1;
00819   }
00820 }
00821 
00822 
00823 void ANARIRender::framebuffer_resize(int fbwidth, int fbheight) {
00824   DBG();
00825   if (!context_created)
00826     return;
00827 
00828   width = fbwidth;
00829   height = fbheight;
00830 
00831   if (buffers_allocated) {
00832     if (verbose == RT_VERB_DEBUG) 
00833       printf("ANARIRenderer) framebuffer_resize(%d x %d)\n", width, height);
00834     framebuffer_destroy();
00835   }
00836 
00837   // XXX for ANARI framebuffer setup is completely deferred to render-time
00838 
00839   buffers_allocated = 1;
00840 }
00841 
00842 
00843 void ANARIRender::framebuffer_destroy() {
00844   DBG();
00845   if (!context_created)
00846     return;
00847 
00848 //  if (buffers_allocated) {
00849     // XXX for ANARI framebuffer teardown is done just after unmapping
00850 //  }
00851   buffers_allocated = 0;
00852 }
00853 
00854 
00855 
00856 void ANARIRender::commit_rep() {
00857 #if defined(VMDANARIREPGROUPING)
00858   int i;
00859   int nmeshbufs = trimesh_v3f_n3f_c3f.num() - lastrepmesh;
00860   int nspherebufs = spheres_color.num() - lastrepspheres;
00861   int ncylbufs = cylinders_color.num() - lastrepcyls;
00862   int numsurfs = nmeshbufs + nspherebufs + ncylbufs;
00863 
00864   if (verbose == RT_VERB_DEBUG)
00865     printf("ANARIRenderer) Committing rep, %d surfs: %d meshbufs, %d spbufs, %d cylbufs\n", numsurfs, nmeshbufs, nspherebufs, ncylbufs);
00866 
00867   if (numsurfs < 1)
00868     return;
00869 
00870   ANARISurface *surfs = (ANARISurface *) calloc(1, numsurfs * sizeof(ANARISurface));
00871   surfbufs.append(surfs);
00872   int cursurf=0;
00873 
00874   // commit triangle mesh geometry after assigning materials
00875   for (i=lastrepmesh; i<trimesh_v3f_n3f_c3f.num(); i++) {
00876     if (verbose == RT_VERB_DEBUG)
00877       printf("ANARIRenderer) Adding triangle mesh[%d]: %d tris ...\n", 
00878              i, trimesh_v3f_n3f_c3f[i].num);
00879  
00880     surfs[cursurf++] = trimesh_v3f_n3f_c3f[i].surf;
00881   } 
00882   lastrepmesh=trimesh_v3f_n3f_c3f.num();
00883 
00884 
00885   // commit sphere geometry after assigning materials
00886   for (i=lastrepspheres; i<spheres_color.num(); i++) {
00887     if (verbose == RT_VERB_DEBUG)
00888       printf("ANARIRenderer) Adding sphere_color array [%d]: %d spheres ...\n",
00889              i, spheres_color[i].num);
00890 
00891     surfs[cursurf++] = spheres_color[i].surf;
00892   } 
00893   lastrepspheres=spheres_color.num();
00894 
00895 
00896   // commit cylinder geometry after assigning materials
00897   for (i=lastrepcyls; i<cylinders_color.num(); i++) {
00898     if (verbose == RT_VERB_DEBUG)
00899       printf("ANARIRenderer) Adding cylinders_color array [%d]: %d cylinders...\n",
00900              i, cylinders_color[i].num);
00901 
00902     surfs[cursurf++] = cylinders_color[i].surf;
00903   }
00904   lastrepcyls=cylinders_color.num();
00905 
00906 
00907   // add all of the prims to the same group/instance
00908   ANARIGroup group = anariNewGroup(dev);
00909 #if 1
00910 printf("ANARIRenderer) Assigning group name.\n");
00911   // if using the USD back-end, assign the "name" tag for the geom...
00912   if (rendererworkarounds == ANARI_USD && (strlen(lastcommentstring) > 0)) {
00913     char strbuf[2048];
00914     sprintf(strbuf, "%s_seqgrp%d", lastcommentstring, seqgrp);
00915     anariSetParameter(dev, group, "name", ANARI_STRING, strbuf);
00916     seqgrp++; 
00917   }
00918 #endif
00919 
00920 printf("ANARIRenderer) Generating surface array...\n");
00921   ANARIArray1D surfobj = anariNewArray1D(dev, &surfs[0], 0, 0, ANARI_SURFACE, numsurfs, 0);
00922   anariCommit(dev, surfobj);
00923 
00924 printf("ANARIRenderer) Generating group.\n");
00925   anariSetParameter(dev, group, "surface", ANARI_ARRAY1D, &surfobj);
00926 
00927 printf("ANARIRenderer) Committing group.\n");
00928   anariCommit(dev, group); 
00929   anariRelease(dev, surfobj);
00930 
00931   for (i=0; i<numsurfs; i++) {
00932     anariRelease(dev, surfs[i]);
00933   }
00934 
00935   ANARIInstance instance = anariNewInstance(dev);
00936   anariSetParameter(dev, instance, "group", ANARI_GROUP, &group);
00937   anariCommit(dev, instance);
00938   anariRelease(dev, group);
00939 
00940   anariInstances.append(instance);
00941 #endif
00942 }
00943 
00944 
00945 void ANARIRender::render_compile_and_validate(void) {
00946   int i;
00947 
00948   DBG();
00949   if (!context_created)
00950     return;
00951 
00952   //
00953   // finalize context validation, compilation, and AS generation 
00954   //
00955   double startctxtime = wkf_timer_timenow(anr_timer);
00956 
00957   // XXX any last ANARI state updates/checks
00958 
00959   // commit the final bit of accumulated rep geometry if not already...
00960   commit_rep();
00961 
00962   if ((anariWorld = anariNewWorld(dev)) == NULL) {
00963     printf("ANARIRenderer) Failed to create new world!\n");
00964   }
00965 
00966   if (verbose == RT_VERB_DEBUG)
00967     printf("ANARIRenderer) num spheres = %ld\n", spheres_color.num());
00968 
00969 
00970   // 
00971   // Set camera parms
00972   // 
00973   float cam_pos_orig[3] = {0.0f, 0.0f, 2.0f};
00974   float cam_U_orig[3] = {1.0f, 0.0f, 0.0f};
00975   float cam_V_orig[3] = {0.0f, 1.0f, 0.0f};
00976   float cam_W_orig[3] = {0.0f, 0.0f, -1.0f};
00977 
00978   float cam_pos[3], cam_U[3], cam_V[3], cam_W[3];
00979   vec_copy(cam_pos, cam_pos_orig);
00980   vec_copy(cam_U, cam_U_orig);
00981   vec_copy(cam_V, cam_V_orig);
00982   vec_copy(cam_W, cam_W_orig);
00983 
00984   if (camera_projection == ANARIRender::RT_ORTHOGRAPHIC) {
00985     if(!anariCamera) anariCamera = anariNewCamera(dev, "orthographic");
00986 
00987     float orthoheight = 2.0f * cam_zoom;
00988     anariSetParameter(dev, anariCamera, "height", ANARI_FLOAT32, &orthoheight);
00989 
00990     if (dof_enabled) {
00991       msgWarn << "ANARIRenderer) DoF not implemented for orthographic camera!" << sendmsg;
00992     }
00993   } else {
00994     if(!anariCamera) anariCamera = anariNewCamera(dev, "perspective");
00995 
00996     float camfovy = 2.0f*180.0f*(atanf(cam_zoom)/M_PI);
00997     anariSetParameter(dev, anariCamera, "fovy", ANARI_FLOAT32, &camfovy);
00998 
00999     if (dof_enabled) {
01000       anariSetParameter(dev, anariCamera, "focusDistance", ANARI_FLOAT32, &cam_dof_focal_dist);
01001       float dofaprad = cam_dof_focal_dist / (2.0f * cam_zoom * cam_dof_fnumber);
01002       anariSetParameter(dev, anariCamera, "apertureRadius", ANARI_FLOAT32, &dofaprad);
01003     } else {
01004       float dofaprad = 0.0f;
01005       anariSetParameter(dev, anariCamera, "apertureRadius", ANARI_FLOAT32, &dofaprad);
01006     }
01007   }
01008 
01009   if (anariCamera) {
01010     float camaspect = width / ((float) height); 
01011     anariSetParameter(dev, anariCamera, "aspect", ANARI_FLOAT32, &camaspect);
01012     anariSetParameter(dev, anariCamera, "position",  ANARI_FLOAT32_VEC3, cam_pos);
01013     anariSetParameter(dev, anariCamera, "direction", ANARI_FLOAT32_VEC3, cam_W);
01014     anariSetParameter(dev, anariCamera, "up",        ANARI_FLOAT32_VEC3, cam_V);
01015     anariCommit(dev, anariCamera);
01016   }
01017 
01018   // 
01019   // Set framebuffer 
01020   // 
01021   framebuffer_config(width, height);
01022 
01023   //
01024   // Set all lights
01025   //
01026   if (verbose == RT_VERB_DEBUG)
01027     printf("ANARIRenderer) setting lights...\n");
01028 
01029   // The direct lighting scaling factor all of the other lights.
01030   float lightscale = 1.0f;
01031   if (ao_samples != 0)
01032     lightscale = ao_direct;
01033 
01034   for (i = 0; i < directional_lights.num(); ++i) {
01035     ANARILight light = anariNewLight(dev, "directional");
01036     anariSetParameter(dev, light, "color", ANARI_FLOAT32_VEC3, directional_lights[i].color);
01037 
01038 //      // The direct lighting scaling factor is applied to the lights here.
01039 //      anariSetParameter(dev, light, "intensity", ANARI_FLOAT32, &lightscale);
01040 
01041     // ANARI uses a light direction vector opposite to VMD and Tachyon 
01042     float lightDir[3];
01043     vec_negate(lightDir, directional_lights[i].dir);
01044     vec_normalize(lightDir); // just for good measure
01045     anariSetParameter(dev, light, "direction", ANARI_FLOAT32_VEC3, lightDir);
01046     anariCommit(dev, light);
01047     anariLights.append(light);
01048   }
01049 
01050   // 
01051   // update renderer state
01052   //
01053 
01054   // AO scaling factor is applied to a special ambient light.
01055   if (ao_samples != 0) {
01056     // ANARI spec puts AO on renderers, not as a light object
01057     if (getenv("VMDANARIDEVICE") && !strcmp(getenv("VMDANARIDEVICE"), "visrtx")) {
01058       float tmp = ao_ambient * 1.5f;
01059       anariSetParameter(dev, anariRenderer, "ambientLight", ANARI_FLOAT32, &tmp);
01060     } else {
01061       ANARILight light = anariNewLight(dev, "ambient");
01062   
01063       // AO scaling factor is applied to the special ambient light
01064       anariSetParameter(dev, light, "intensity", ANARI_FLOAT32, &ao_ambient);
01065  
01066       float whitecol[] = { 1.0f, 1.0f, 1.0f };
01067       anariSetParameter(dev, light, "color", ANARI_FLOAT32_VEC3, whitecol);
01068   
01069       anariCommit(dev, light);
01070       anariLights.append(light); // add AO ambient light
01071     }
01072   } 
01073 
01074   if (verbose == RT_VERB_DEBUG)
01075     printf("ANARIRenderer) setting sample counts...\n");
01076 
01077   // ANARI uses VEC4F only for background colors
01078   float bgcoltmp[4];
01079   vec_copy(bgcoltmp, scene_bg_color);
01080   bgcoltmp[3] = 1.0f;
01081   anariSetParameter(dev, anariRenderer, "backgroundColor", ANARI_FLOAT32_VEC4, bgcoltmp);
01082 
01083   if (rendererworkarounds != ANARI_USD) {
01084     if (ao_samples && interactive_renderer) {
01085       const int one = 1;
01086       anariSetParameter(dev, anariRenderer, "pixelSamples", ANARI_INT32, &one); // all renderers
01087       if (anari_rendermode == ANARI_SCIVIS)
01088         anariSetParameter(dev, anariRenderer, "aoSamples", ANARI_INT32, &one);    // scivis-only
01089     } else {
01090       anariSetParameter(dev, anariRenderer, "pixelSamples", ANARI_INT32, &aa_samples); // all renderers
01091       if (anari_rendermode == ANARI_SCIVIS)
01092         anariSetParameter(dev, anariRenderer, "aoSamples", ANARI_INT32, &ao_samples);    // scivis-only
01093     }
01094 
01095     if (getenv("VMDANARIAOMAXDIST")) {
01096       float tmp = atof(getenv("VMDANARIAOMAXDIST"));
01097       if (verbose == RT_VERB_DEBUG) {
01098         printf("ANARIRenderer) setting AO maxdist: %f\n", tmp);
01099       }
01100       anariSetParameter(dev, anariRenderer, "aoRadius", ANARI_FLOAT32, &tmp); // scivis-only
01101     }
01102   }
01103 
01104   if (rendererworkarounds != ANARI_USD) {
01105 #if 1
01106     // XXX ANARI doesn't support rendering w/o shadows presently
01107     // render with/without shadows
01108     msgInfo << "Shadow rendering enabled." << sendmsg;
01109 #else
01110     if (shadows_enabled || ao_samples) {
01111       if (shadows_enabled && !ao_samples)
01112         msgInfo << "Shadow rendering enabled." << sendmsg;
01113 
01114       const int one = 1;
01115       anariSetParameter(dev, anariRenderer, "shadowsEnabled", ANARI_INT32, &one);
01116     } else {
01117       const int zero = 0;
01118       anariSetParameter(dev, anariRenderer, "shadowsEnabled", ANARI_INT32, &zero);
01119     }
01120 #endif
01121   }
01122 
01123   // render with ambient occlusion, but only if shadows are also enabled
01124   if (ao_samples) {
01125     msgInfo << "Ambient occlusion enabled." << sendmsg;
01126 //    msgInfo << "Shadow rendering enabled." << sendmsg;
01127   }
01128 
01129   if (verbose == RT_VERB_DEBUG)
01130     printf("ANARIRenderer) Committing geometry buffers...\n");
01131 
01132 #if !defined(VMDANARIREPGROUPING)
01133   if (verbose == RT_VERB_DEBUG)
01134     printf("ANARIRenderer) Committing %ld trimesh buffers...\n", trimesh_v3f_n3f_c3f.num());
01135 
01136   // commit triangle mesh geometry after assigning materials
01137   for (i=0; i<trimesh_v3f_n3f_c3f.num(); i++) {
01138     if (verbose == RT_VERB_DEBUG)
01139       printf("ANARIRenderer) Adding triangle mesh[%d]: %d tris ...\n", 
01140              i, trimesh_v3f_n3f_c3f[i].num);
01141  
01142     ANARIGroup group = anariNewGroup(dev);
01143 #if 1
01144     // if using the USD back-end, assign the "name" tag for the geom...
01145     if (rendererworkarounds == ANARI_USD && (strlen(lastcommentstring) > 0)) {
01146  //     printf("ANARIRenderer)    Mesh: '%s'\n", lastcommentstring);
01147 
01148       char strbuf[2048];
01149       sprintf(strbuf, "%s_seqgrp%d", lastcommentstring, seqgrp);
01150       anariSetParameter(dev, group, "name", ANARI_STRING, strbuf);
01151       seqgrp++; 
01152     }
01153 #endif
01154     ANARIArray1D surfs = anariNewArray1D(dev, &trimesh_v3f_n3f_c3f[i].surf, 0, 0, ANARI_SURFACE, 1, 0);
01155     anariCommit(dev, surfs);
01156     anariRelease(dev, trimesh_v3f_n3f_c3f[i].surf);
01157     anariSetParameter(dev, group, "surface", ANARI_ARRAY1D, &surfs);
01158     anariCommit(dev, group);
01159     anariRelease(dev, surfs);
01160 
01161     ANARIInstance instance = anariNewInstance(dev);
01162     anariSetParameter(dev, instance, "group", ANARI_GROUP, &group);
01163     anariCommit(dev, instance);
01164     anariRelease(dev, group);
01165 
01166     anariInstances.append(instance);
01167   } 
01168 
01169   if (verbose == RT_VERB_DEBUG)
01170     printf("ANARIRenderer) Committing %ld sphere buffers...\n", spheres_color.num());
01171 
01172   // commit sphere geometry after assigning materials
01173   for (i=0; i<spheres_color.num(); i++) {
01174     if (verbose == RT_VERB_DEBUG)
01175       printf("ANARIRenderer) Adding sphere_color array [%d]: %d spheres ...\n",
01176              i, spheres_color[i].num);
01177 
01178     ANARIGroup group = anariNewGroup(dev);
01179 #if 1
01180     // if using the USD back-end, assign the "name" tag for the geom...
01181     if (rendererworkarounds == ANARI_USD && (strlen(lastcommentstring) > 0)) {
01182 //      printf("ANARIRenderer)    SphereArray: '%s'\n", lastcommentstring);
01183 
01184       char strbuf[2048];
01185       sprintf(strbuf, "%s_seqgrp%d", lastcommentstring, seqgrp);
01186       anariSetParameter(dev, group, "name", ANARI_STRING, strbuf);
01187       seqgrp++; 
01188     }
01189 #endif
01190     ANARIArray1D surfs = anariNewArray1D(dev, &spheres_color[i].surf, 0, 0, ANARI_SURFACE, 1, 0);
01191     anariCommit(dev, surfs);
01192     anariRelease(dev, spheres_color[i].surf);
01193     anariSetParameter(dev, group, "surface", ANARI_ARRAY1D, &surfs);
01194     anariCommit(dev, group); 
01195     anariRelease(dev, surfs);
01196 
01197     ANARIInstance instance = anariNewInstance(dev);
01198     anariSetParameter(dev, instance, "group", ANARI_GROUP, &group);
01199     anariCommit(dev, instance);
01200     anariRelease(dev, group);
01201 
01202     anariInstances.append(instance);
01203   } 
01204 
01205   if (verbose == RT_VERB_DEBUG)
01206     printf("ANARIRenderer) Committing %ld cylinder buffers...\n", cylinders_color.num());
01207 
01208   // commit cylinder geometry after assigning materials
01209   for (i=0; i<cylinders_color.num(); i++) {
01210     if (verbose == RT_VERB_DEBUG)
01211       printf("ANARIRenderer) Adding cylinders_color array [%d]: %d cylinders...\n",
01212              i, cylinders_color[i].num);
01213 
01214     ANARIGroup group = anariNewGroup(dev);
01215 #if 1
01216     // if using the USD back-end, assign the "name" tag for the geom...
01217     if (rendererworkarounds == ANARI_USD && (strlen(lastcommentstring) > 0)) {
01218 //      printf("ANARIRenderer)    CylinderArray: '%s'\n", lastcommentstring);
01219 
01220       char strbuf[2048];
01221       sprintf(strbuf, "%s_seqgrp%d", lastcommentstring, seqgrp);
01222       anariSetParameter(dev, group, "name", ANARI_STRING, strbuf);
01223       seqgrp++; 
01224     }
01225 #endif
01226     ANARIArray1D surfs = anariNewArray1D(dev, &cylinders_color[i].surf, 0, 0, ANARI_SURFACE, 1, 0);
01227     anariCommit(dev, surfs);
01228     anariRelease(dev, cylinders_color[i].surf);
01229     anariSetParameter(dev, group, "surface", ANARI_ARRAY1D, &surfs);
01230     anariCommit(dev, group); 
01231     anariRelease(dev, surfs);
01232 
01233     ANARIInstance instance = anariNewInstance(dev);
01234     anariSetParameter(dev, instance, "group", ANARI_GROUP, &group);
01235     anariCommit(dev, instance);
01236     anariRelease(dev, group);
01237 
01238     anariInstances.append(instance);
01239   }
01240 #endif
01241 
01242 
01243   if (verbose == RT_VERB_DEBUG)
01244     printf("ANARIRenderer) Attaching instances to scene...\n");
01245 
01246   // attach all instances to the scene...
01247   ANARIArray1D instances = anariNewArray1D(dev, &anariInstances[0], 0, 0, ANARI_INSTANCE, anariInstances.num(), 0);
01248   anariCommit(dev, instances);
01249   anariSetParameter(dev, anariWorld, "instance", ANARI_ARRAY1D, &instances);
01250   anariRelease(dev, instances);
01251   for (i=0; i<anariInstances.num(); i++) {
01252     anariRelease(dev, anariInstances[i]);
01253   }
01254   anariInstances.clear();
01255 
01256   if (verbose == RT_VERB_DEBUG)
01257     printf("ANARIRenderer) Attaching %ld lights to scene...\n", anariLights.num());
01258 
01259   if (verbose == RT_VERB_DEBUG)
01260     printf("ANARIRenderer) Committing anariWorld...\n");
01261 
01262   // if using the USD back-end, assign the "name" tag for the geom...
01263   if (rendererworkarounds == ANARI_USD && (strlen(lastcommentstring) > 0)) {
01264     anariSetParameter(dev, anariWorld, "name", ANARI_STRING, "VMD World");
01265   }
01266 
01267   if (anariLights.num() > 0) {
01268     // attach all lights to the scene...
01269     ANARIArray1D lights = anariNewArray1D(dev, &anariLights[0], 0, 0, ANARI_LIGHT, anariLights.num(), 0);
01270     anariCommit(dev, lights);
01271     anariSetParameter(dev, anariWorld, "light", ANARI_ARRAY1D, &lights);
01272     anariCommit(dev, anariWorld); // commit the completed scene
01273     anariRelease(dev, lights);
01274   } else {
01275     anariCommit(dev, anariWorld); // commit the completed scene
01276   }
01277 
01278   // print out world bounds
01279   float worldBounds[6] = {};
01280   if (anariGetProperty(dev, anariWorld, "bounds", ANARI_FLOAT32_BOX3, 
01281                        worldBounds, sizeof(worldBounds), ANARI_WAIT)) {
01282     printf("ANARIRenderer) world bounds: ({%f, %f, %f}, {%f, %f, %f}\n\n",
01283            worldBounds[0], worldBounds[1], worldBounds[2],
01284            worldBounds[3], worldBounds[4], worldBounds[5]);
01285   }
01286 
01287   if (verbose == RT_VERB_DEBUG)
01288     printf("ANARIRenderer) Committing anariRenderer...\n");
01289 
01290   anariCommit(dev, anariRenderer);
01291 
01292   if (verbose == RT_VERB_DEBUG) printf("ANARIRenderer) Finalizing ANARI rendering kernels...\n");
01293   // XXX any last ANARI state updates/checks
01294 
01295   double contextinittime = wkf_timer_timenow(anr_timer);
01296   time_ctx_validate = contextinittime - startctxtime;
01297 
01298   //
01299   // Force ANARI to build the acceleration structure _now_, so we can time it
01300   //
01301   // XXX No way to force-build ANARI AS for timing?
01302 
01303   time_ctx_AS_build = wkf_timer_timenow(anr_timer) - contextinittime;
01304   if (verbose == RT_VERB_DEBUG) {
01305     printf("ANARIRenderer) launching render: %d x %d\n", width, height);
01306   }
01307 }
01308 
01309 
01310 #if defined(VMDANARI_INTERACTIVE_OPENGL)
01311 
01312 static void *createanariraywindow(const char *wintitle, int width, int height) {
01313   printf("ANARIRenderer) Creating ANARI window: %d x %d...\n", width, height);
01314 
01315   void *win = glwin_create(wintitle, width, height);
01316   while (glwin_handle_events(win, GLWIN_EV_POLL_NONBLOCK) != 0);
01317 
01318   glDrawBuffer(GL_BACK);
01319   glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
01320   glClearColor(0.0, 0.0, 0.0, 1.0); /* black */
01321   glViewport(0, 0, width, height);
01322   glClear(GL_COLOR_BUFFER_BIT);
01323 
01324   glShadeModel(GL_FLAT);
01325   glMatrixMode(GL_PROJECTION);
01326   glLoadIdentity();
01327   glOrtho(0.0, width, height, 0.0, -1.0, 1.0);
01328   glMatrixMode(GL_MODELVIEW);
01329   glLoadIdentity();
01330 
01331   glDrawBuffer(GL_BACK);
01332   glClear(GL_COLOR_BUFFER_BIT);
01333 
01334   glwin_swap_buffers(win);
01335 
01336   return win;
01337 }
01338 
01339 
01340 static void interactive_viewer_usage(void *win) {
01341   printf("ANARIRenderer) VMD TachyonL-ANARI Interactive Ray Tracer help:\n");
01342   printf("ANARIRenderer) ================================================\n");
01343 
01344   // check for Spaceball/SpaceNavigator/Magellan input devices
01345   int havespaceball = ((glwin_spaceball_available(win)) && (getenv("VMDDISABLESPACEBALLXDRV") == NULL));
01346   printf("ANARIRenderer) Spaceball/SpaceNavigator/Magellan: %s\n",
01347          (havespaceball) ? "Available" : "Not available");
01348 
01349   // check for stereo-capable display
01350   int havestereo, havestencil;
01351   glwin_get_wininfo(win, &havestereo, &havestencil);
01352   printf("ANARIRenderer) Stereoscopic display: %s\n",
01353          (havestereo) ? "Available" : "Not available");
01354 
01355   // check for vertical retrace sync
01356   int vsync=0, rc=0;
01357   if ((rc = glwin_query_vsync(win, &vsync)) == GLWIN_SUCCESS) {
01358     printf("ANARIRenderer) Vert retrace sync: %s\n", (vsync) ? "On" : "Off");
01359   } else {
01360     printf("ANARIRenderer) Vert retrace sync: indeterminate\n");
01361   }
01362 
01363   printf("ANARIRenderer)\n");
01364   printf("ANARIRenderer) General controls:\n");
01365   printf("ANARIRenderer)   space: save numbered snapshot image\n");
01366   printf("ANARIRenderer)       =: reset to initial view\n");
01367   printf("ANARIRenderer)       h: print this help info\n");
01368   printf("ANARIRenderer)       p: print current rendering parameters\n");
01369   printf("ANARIRenderer)   ESC,q: quit viewer\n");
01370   printf("ANARIRenderer)\n");
01371   printf("ANARIRenderer) Display controls\n");
01372   printf("ANARIRenderer)      F1: override shadows on/off (off=AO off too)\n");
01373   printf("ANARIRenderer)      F2: override AO on/off\n");
01374   printf("ANARIRenderer)      F3: override DoF on/off\n");
01375   printf("ANARIRenderer)      F4: override Depth cueing on/off\n");
01376 // Not currently applicable to ANARI
01377 // #ifdef USE_REVERSE_SHADOW_RAYS
01378 //   printf("ANARIRenderer)      F5: enable/disable shadow ray optimizations\n");
01379 // #endif
01380   printf("ANARIRenderer)     F12: toggle full-screen display on/off\n");
01381   printf("ANARIRenderer)   1-9,0: override samples per update auto-FPS off\n");
01382   printf("ANARIRenderer)      Up: increase DoF focal distance\n");
01383   printf("ANARIRenderer)    Down: decrease DoF focal distance\n");
01384   printf("ANARIRenderer)    Left: decrease DoF f/stop\n");
01385   printf("ANARIRenderer)   Right: increase DoF f/stop\n");
01386   printf("ANARIRenderer)       S: toggle stereoscopic display on/off (if avail)\n");
01387   printf("ANARIRenderer)       a: toggle AA/AO auto-FPS tuning on/off (on)\n");
01388   printf("ANARIRenderer)       g: toggle gradient sky xforms on/off (on)\n");
01389   printf("ANARIRenderer)       l: toggle light xforms on/off (on)\n");
01390   printf("ANARIRenderer)\n");
01391   printf("ANARIRenderer) Mouse controls:\n");
01392   printf("ANARIRenderer)       f: mouse depth-of-field mode\n");
01393   printf("ANARIRenderer)       r: mouse rotation mode\n");
01394   printf("ANARIRenderer)       s: mouse scaling mode\n");
01395   printf("ANARIRenderer)       t: mouse translation mode\n");
01396 
01397   int movie_recording_enabled = (getenv("VMDANARILIVEMOVIECAPTURE") != NULL);
01398   if (movie_recording_enabled) {
01399     printf("ANARIRenderer)\n");
01400     printf("ANARIRenderer) Movie recording controls:\n");
01401     printf("ANARIRenderer)       R: start/stop movie recording\n");
01402     printf("ANARIRenderer)       F: toggle movie FPS (24, 30, 60)\n");
01403   }
01404 }
01405 
01406 
01407 void ANARIRender::render_to_glwin(const char *filename) {
01408   DBG();
01409   int i;
01410 
01411   if (!context_created)
01412     return;
01413 
01414   enum RtMouseMode { RTMM_ROT=0, RTMM_TRANS=1, RTMM_SCALE=2, RTMM_DOF=3 };
01415   enum RtMouseDown { RTMD_NONE=0, RTMD_LEFT=1, RTMD_MIDDLE=2, RTMD_RIGHT=3 };
01416   RtMouseMode mm = RTMM_ROT;
01417   RtMouseDown mousedown = RTMD_NONE;
01418 
01419   // flags to interactively enable/disable shadows, AO, DoF
01420   int gl_shadows_on=(shadows_enabled) ? RT_SHADOWS_ON : RT_SHADOWS_OFF;
01421 
01422   int gl_fs_on=0; // fullscreen window state
01423   int owsx=0, owsy=0; // store last win size before fullscreen
01424   int gl_ao_on=(ao_samples > 0);
01425   int gl_dof_on, gl_dof_on_old;
01426   gl_dof_on=gl_dof_on_old=dof_enabled; 
01427   int gl_fog_on=(fog_mode != RT_FOG_NONE);
01428 
01429   // Enable live recording of a session to a stream of image files indexed
01430   // by their display presentation time, mapped to the nearest frame index
01431   // in a fixed-frame-rate image sequence (e.g. 24, 30, or 60 FPS), 
01432   // to allow subsequent encoding into a standard movie format.
01433   // XXX this feature is disabled by default at present, to prevent people
01434   //     from accidentally turning it on during a live demo or the like
01435   int movie_recording_enabled = (getenv("VMDANARILIVEMOVIECAPTURE") != NULL);
01436   int movie_recording_on = 0;
01437   double movie_recording_start_time = 0.0;
01438   int movie_recording_fps = 30;
01439   int movie_framecount = 0;
01440   int movie_lastframeindex = 0;
01441   const char *movie_recording_filebase = "vmdlivemovie.%05d.tga";
01442   if (getenv("VMDANARILIVEMOVIECAPTUREFILEBASE"))
01443     movie_recording_filebase = getenv("VMDANARILIVEMOVIECAPTUREFILEBASE");
01444 
01445   // Enable/disable Spaceball/SpaceNavigator/Magellan input 
01446   int spaceballenabled=(getenv("VMDDISABLESPACEBALLXDRV") == NULL) ? 1 : 0;
01447   int spaceballmode=0;       // default mode is rotation/translation
01448   int spaceballflightmode=0; // 0=moves object, 1=camera fly
01449   if (getenv("VMDANARISPACEBALLFLIGHT"))
01450     spaceballflightmode=1;
01451 
01452 
01453   // total AA/AO sample count
01454   int totalsamplecount=0;
01455 
01456   // counter for snapshots of live image...
01457   int snapshotcount=0;
01458 
01459   // flag to enable automatic AO sample count adjustment for FPS rate control
01460   int autosamplecount=1;
01461 
01462   // flag to enable transformation of lights and gradient sky sphere, 
01463   // so that they track camera orientation as they do in the VMD OpenGL display
01464   int xformlights=1, xformgradientsphere=1;
01465 
01466   //
01467   // allocate or reconfigure the framebuffer, accumulation buffer, 
01468   // and output streams required for progressive rendering, either
01469   // using the new progressive APIs, or using our own code.
01470   //
01471   // Unless overridden by environment variables, we use the incoming
01472   // window size parameters from VMD to initialize the RT image dimensions.
01473   // If image size is overridden, often when using HMDs, the incoming 
01474   // dims are window dims are used to size the GL window, but the image size
01475   // is set independently.
01476   int wsx=width, wsy=height;
01477   const char *imageszstr = getenv("VMDANARIIMAGESIZE");
01478   if (imageszstr) {
01479     if (sscanf(imageszstr, "%d %d", &width, &height) != 2) {
01480       width=wsx;
01481       height=wsy;
01482     } 
01483   } 
01484   framebuffer_config(width, height);
01485 
01486   // prepare the majority of ANARI rendering state before we go into 
01487   // the interactive rendering loop
01488   update_rendering_state(1);
01489   render_compile_and_validate();
01490 
01491   // make a copy of state we're going to interactively manipulate,
01492   // so that we can recover to the original state on-demand
01493   int samples_per_pass = 1;
01494   int cur_aa_samples = aa_samples;
01495   int cur_ao_samples = ao_samples;
01496   float cam_zoom_orig = cam_zoom;
01497   float scene_gradient_orig[3] = {0.0f, 1.0f, 0.0f};
01498   vec_copy(scene_gradient_orig, scene_gradient);
01499 
01500   float cam_pos_orig[3] = {0.0f, 0.0f, 2.0f};
01501   float cam_U_orig[3] = {1.0f, 0.0f, 0.0f};
01502   float cam_V_orig[3] = {0.0f, 1.0f, 0.0f};
01503   float cam_W_orig[3] = {0.0f, 0.0f, -1.0f};
01504   float cam_pos[3], cam_U[3], cam_V[3], cam_W[3];
01505   float hmd_U[3], hmd_V[3], hmd_W[3];
01506 
01507   vec_copy(cam_pos, cam_pos_orig);
01508   vec_copy(cam_U, cam_U_orig);
01509   vec_copy(cam_V, cam_V_orig);
01510   vec_copy(cam_W, cam_W_orig);
01511 
01512   // copy light directions
01513   anr_directional_light *cur_dlights = (anr_directional_light *) calloc(1, directional_lights.num() * sizeof(anr_directional_light));
01514   for (i=0; i<directional_lights.num(); i++) {
01515     vec_copy((float*)&cur_dlights[i].color, directional_lights[i].color);
01516     vec_copy((float*)&cur_dlights[i].dir, directional_lights[i].dir);
01517     vec_normalize((float*)&cur_dlights[i].dir);
01518   }
01519 
01520   // create the display window
01521   void *win = createanariraywindow("VMD TachyonL-ANARI Interactive Ray Tracer", width, height);
01522   interactive_viewer_usage(win);
01523   
01524   // check for stereo-capable display
01525   int havestereo=0, havestencil=0;
01526   int stereoon=0, stereoon_old=0;
01527   glwin_get_wininfo(win, &havestereo, &havestencil);
01528 
01529   // Override AA/AO sample counts since we're doing progressive rendering.
01530   // Choosing an initial AO sample count of 1 will give us the peak progressive 
01531   // display update rate, but we end up wasting time on re-tracing many
01532   // primary rays.  The automatic FPS optimization scheme below will update
01533   // the number of samples per rendering pass and assign the best values for
01534   // AA/AO samples accordingly.
01535   cur_aa_samples = samples_per_pass;
01536   if (cur_ao_samples > 0) {
01537     cur_aa_samples = 1;
01538     cur_ao_samples = samples_per_pass;
01539   }
01540 
01541   const char *statestr = "|/-\\.";
01542   int done=0, winredraw=1, accum_count=0;
01543   int state=0, mousedownx=0, mousedowny=0;
01544   float cur_cam_zoom = cam_zoom_orig;
01545 
01546   double fpsexpave=0.0; 
01547   
01548   double oldtime = wkf_timer_timenow(anr_timer);
01549   while (!done) { 
01550     int winevent=0;
01551 
01552     while ((winevent = glwin_handle_events(win, GLWIN_EV_POLL_NONBLOCK)) != 0) {
01553       int evdev, evval;
01554       char evkey;
01555 
01556       glwin_get_lastevent(win, &evdev, &evval, &evkey);
01557       glwin_get_winsize(win, &wsx, &wsy);
01558 
01559       if (evdev == GLWIN_EV_WINDOW_CLOSE) {
01560         printf("ANARIRenderer) display window closed, exiting...\n");
01561         done = 1;
01562         winredraw = 0;
01563       } else if (evdev == GLWIN_EV_KBD) {
01564         switch (evkey) {
01565           case  '1': autosamplecount=0; samples_per_pass=1; winredraw=1; break;
01566           case  '2': autosamplecount=0; samples_per_pass=2; winredraw=1; break;
01567           case  '3': autosamplecount=0; samples_per_pass=3; winredraw=1; break;
01568           case  '4': autosamplecount=0; samples_per_pass=4; winredraw=1; break;
01569           case  '5': autosamplecount=0; samples_per_pass=5; winredraw=1; break;
01570           case  '6': autosamplecount=0; samples_per_pass=6; winredraw=1; break;
01571           case  '7': autosamplecount=0; samples_per_pass=7; winredraw=1; break;
01572           case  '8': autosamplecount=0; samples_per_pass=8; winredraw=1; break;
01573           case  '9': autosamplecount=0; samples_per_pass=9; winredraw=1; break;
01574           case  '0': autosamplecount=0; samples_per_pass=10; winredraw=1; break;
01575 
01576           case  '=': /* recover back to initial state */
01577             vec_copy(scene_gradient, scene_gradient_orig);
01578             cam_zoom = cam_zoom_orig;
01579             vec_copy(cam_pos, cam_pos_orig);
01580             vec_copy(cam_U, cam_U_orig);
01581             vec_copy(cam_V, cam_V_orig);
01582             vec_copy(cam_W, cam_W_orig);
01583 
01584             // restore original light directions
01585             for (i=0; i<directional_lights.num(); i++) {
01586               vec_copy((float*)&cur_dlights[i].dir, directional_lights[i].dir);
01587               vec_normalize((float*)&cur_dlights[i].dir);
01588             }
01589             winredraw = 1;
01590             break;
01591  
01592           case  ' ': /* spacebar saves current image with counter */
01593             {
01594               char snapfilename[256];
01595               sprintf(snapfilename, "vmdsnapshot.%04d.tga", snapshotcount);
01596               const unsigned char *FB = (const unsigned char*)anariMapFrame(dev, anariFrameBuffer, "color");
01597               if (write_image_file_rgb4u(snapfilename, FB, width, height)) {
01598                 printf("ANARIRenderer) Failed to write output image!\n");
01599               } else {
01600                 printf("ANARIRenderer) Saved snapshot to '%s'             \n",
01601                        snapfilename);
01602               }
01603               anariUnmapFrame(dev, anariFrameBuffer, "color");
01604               snapshotcount++; 
01605             }
01606             break;
01607 
01608           case  'a': /* toggle automatic sample count FPS tuning */
01609             autosamplecount = !(autosamplecount);
01610             printf("\nANARIRenderer) Automatic AO sample count FPS tuning %s\n",
01611                    (autosamplecount) ? "enabled" : "disabled");
01612             break;
01613 
01614           case  'f': /* DoF mode */
01615             mm = RTMM_DOF;
01616             printf("\nANARIRenderer) Mouse DoF aperture and focal dist. mode\n");
01617             break;
01618 
01619           case  'g': /* toggle gradient sky sphere xforms */
01620             xformgradientsphere = !(xformgradientsphere);
01621             printf("\nANARIRenderer) Gradient sky sphere transformations %s\n",
01622                    (xformgradientsphere) ? "enabled" : "disabled");
01623             break;
01624 
01625           case  'h': /* print help message */
01626             printf("\n");
01627             interactive_viewer_usage(win);
01628             break;
01629 
01630           case  'l': /* toggle lighting xforms */
01631             xformlights = !(xformlights);
01632             printf("\nANARIRenderer) Light transformations %s\n",
01633                    (xformlights) ? "enabled" : "disabled");
01634             break;
01635 
01636           case  'p': /* print current RT settings */
01637             printf("\nANARIRenderer) Current Ray Tracing Parameters:\n"); 
01638             printf("ANARIRenderer) -------------------------------\n"); 
01639             printf("ANARIRenderer) Camera zoom: %f\n", cur_cam_zoom);
01640             printf("ANARIRenderer) Shadows: %s  Ambient occlusion: %s\n",
01641                    (gl_shadows_on) ? "on" : "off",
01642                    (gl_ao_on) ? "on" : "off");
01643             printf("ANARIRenderer) Antialiasing samples per-pass: %d\n",
01644                    cur_aa_samples);
01645             printf("ANARIRenderer) Ambient occlusion samples per-pass: %d\n",
01646                    cur_ao_samples);
01647             printf("ANARIRenderer) Depth-of-Field: %s f/num: %.1f  Foc. Dist: %.2f\n",
01648                    (gl_dof_on) ? "on" : "off", 
01649                    cam_dof_fnumber, cam_dof_focal_dist);
01650             printf("ANARIRenderer) Image size: %d x %d\n", width, height);
01651             break;
01652 
01653           case  'r': /* rotate mode */
01654             mm = RTMM_ROT;
01655             printf("\nANARIRenderer) Mouse rotation mode\n");
01656             break;
01657 
01658           case  's': /* scaling mode */
01659             mm = RTMM_SCALE;
01660             printf("\nANARIRenderer) Mouse scaling mode\n");
01661             break;
01662 
01663           case  'F': /* toggle live movie recording FPS (24, 30, 60) */
01664             if (movie_recording_enabled) {
01665               switch (movie_recording_fps) {
01666                 case 24: movie_recording_fps = 30; break;
01667                 case 30: movie_recording_fps = 60; break;
01668                 case 60:
01669                 default: movie_recording_fps = 24; break;
01670               }
01671               printf("\nANARIRenderer) Movie recording FPS rate: %d\n", 
01672                      movie_recording_fps);
01673             } else {
01674               printf("\nANARIRenderer) Movie recording not available.\n");
01675             }
01676             break;
01677 
01678           case  'R': /* toggle live movie recording mode on/off */
01679             if (movie_recording_enabled) {
01680               movie_recording_on = !(movie_recording_on);
01681               printf("\nANARIRenderer) Movie recording %s\n",
01682                      (movie_recording_on) ? "STARTED" : "STOPPED");
01683               if (movie_recording_on) {
01684                 movie_recording_start_time = wkf_timer_timenow(anr_timer);
01685                 movie_framecount = 0;
01686                 movie_lastframeindex = 0;
01687               } else {
01688                 printf("ANARIRenderer) Encode movie with:\n");
01689                 printf("ANARIRenderer)   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");
01690               }
01691             } else {
01692               printf("\nANARIRenderer) Movie recording not available.\n");
01693             }
01694             break;
01695 
01696           case  'S': /* toggle stereoscopic display mode */
01697             if (havestereo) {
01698               stereoon = (!stereoon);
01699               printf("\nANARIRenderer) Stereoscopic display %s\n",
01700                      (stereoon) ? "enabled" : "disabled");
01701               winredraw = 1;
01702             } else {
01703               printf("\nANARIRenderer) Stereoscopic display unavailable\n");
01704             }
01705             break;
01706  
01707           case  't': /* translation mode */
01708             mm = RTMM_TRANS;
01709             printf("\nANARIRenderer) Mouse translation mode\n");
01710             break;
01711             
01712           case  'q': /* 'q' key */
01713           case  'Q': /* 'Q' key */
01714           case 0x1b: /* ESC key */
01715             printf("\nANARIRenderer) Exiting on user input.               \n");
01716             done=1; /* exit from interactive RT window */
01717             break;
01718         }
01719       } else if (evdev != GLWIN_EV_NONE) {
01720         switch (evdev) {
01721           case GLWIN_EV_KBD_F1: /* turn shadows on/off */
01722             gl_shadows_on=(!gl_shadows_on) ? RT_SHADOWS_ON : RT_SHADOWS_OFF;
01723             // gl_shadows_on = (!gl_shadows_on);
01724             printf("\n");
01725             printf("ANARIRenderer) Shadows %s\n",
01726                    (gl_shadows_on) ? "enabled" : "disabled");
01727             winredraw = 1; 
01728             break;
01729 
01730           case GLWIN_EV_KBD_F2: /* turn AO on/off */
01731             gl_ao_on = (!gl_ao_on); 
01732             printf("\n");
01733             printf("ANARIRenderer) Ambient occlusion %s\n",
01734                    (gl_ao_on) ? "enabled" : "disabled");
01735             winredraw = 1; 
01736             break;
01737 
01738           case GLWIN_EV_KBD_F3: /* turn DoF on/off */
01739             gl_dof_on = (!gl_dof_on);
01740             printf("\n");
01741             if ((camera_projection == RT_ORTHOGRAPHIC) && gl_dof_on) {
01742               gl_dof_on=0; 
01743               printf("ANARIRenderer) Depth-of-field not available in orthographic mode\n");
01744             }
01745             printf("ANARIRenderer) Depth-of-field %s\n",
01746                    (gl_dof_on) ? "enabled" : "disabled");
01747             winredraw = 1;
01748             break;
01749 
01750           case GLWIN_EV_KBD_F4: /* turn fog/depth cueing on/off */
01751             gl_fog_on = (!gl_fog_on); 
01752             printf("\n");
01753             printf("ANARIRenderer) Depth cueing %s\n",
01754                    (gl_fog_on) ? "enabled" : "disabled");
01755             winredraw = 1; 
01756             break;
01757 
01758           case GLWIN_EV_KBD_F12: /* toggle full-screen window on/off */
01759             gl_fs_on = (!gl_fs_on);
01760             printf("\nANARIRenderer) Toggling fullscreen window %s\n",
01761                    (gl_fs_on) ? "on" : "off");
01762             if (gl_fs_on) { 
01763               if (glwin_fullscreen(win, gl_fs_on, 0) == 0) {
01764                 owsx = wsx;
01765                 owsy = wsy;
01766                 glwin_get_winsize(win, &wsx, &wsy);
01767               } else {
01768                 printf("ANARIRenderer) Fullscreen mode note available\n");
01769               }
01770             } else {
01771               glwin_fullscreen(win, gl_fs_on, 0);
01772               glwin_resize(win, owsx, owsy);
01773             }
01774             winredraw = 1; 
01775             break;
01776 
01777           case GLWIN_EV_KBD_UP: /* change depth-of-field focal dist */
01778             cam_dof_focal_dist *= 1.02f; 
01779             printf("\nANARIRenderer) DoF focal dist: %f\n", cam_dof_focal_dist);
01780             winredraw = 1; 
01781             break;
01782 
01783           case GLWIN_EV_KBD_DOWN: /* change depth-of-field focal dist */
01784             cam_dof_focal_dist *= 0.96f; 
01785             if (cam_dof_focal_dist < 0.02f) cam_dof_focal_dist = 0.02f;
01786             printf("\nANARIRenderer) DoF focal dist: %f\n", cam_dof_focal_dist);
01787             winredraw = 1; 
01788             break;
01789 
01790           case GLWIN_EV_KBD_RIGHT: /* change depth-of-field f/stop number */
01791             cam_dof_fnumber += 1.0f; 
01792             printf("\nANARIRenderer) DoF f/stop: %f\n", cam_dof_fnumber);
01793             winredraw = 1; 
01794             break;
01795 
01796           case GLWIN_EV_KBD_LEFT: /* change depth-of-field f/stop number */
01797             cam_dof_fnumber -= 1.0f; 
01798             if (cam_dof_fnumber < 1.0f) cam_dof_fnumber = 1.0f;
01799             printf("\nANARIRenderer) DoF f/stop: %f\n", cam_dof_fnumber);
01800             winredraw = 1; 
01801             break;
01802 
01803           case GLWIN_EV_MOUSE_MOVE:
01804             if (mousedown != RTMD_NONE) {
01805               int x, y;
01806               glwin_get_mousepointer(win, &x, &y);
01807 
01808               float zoommod = 2.0f*cur_cam_zoom/cam_zoom_orig;
01809               float txdx = (x - mousedownx) * zoommod / wsx;
01810               float txdy = (y - mousedowny) * zoommod / wsy;
01811               if (mm != RTMM_SCALE) {
01812                 mousedownx = x;
01813                 mousedowny = y;
01814               }
01815 
01816               if (mm == RTMM_ROT) {
01817                 Matrix4 rm;
01818                 if (mousedown == RTMD_LEFT) {
01819                   // when zooming in further from the initial view, we
01820                   // rotate more slowly so control remains smooth
01821                   rm.rotate_axis(cam_V, -txdx);
01822                   rm.rotate_axis(cam_U, -txdy);
01823                 } else if (mousedown == RTMD_MIDDLE || 
01824                            mousedown == RTMD_RIGHT) {
01825                   rm.rotate_axis(cam_W, txdx);
01826                 }
01827                 rm.multpoint3d(cam_pos, cam_pos);
01828                 rm.multnorm3d(cam_U, cam_U);
01829                 rm.multnorm3d(cam_V, cam_V);
01830                 rm.multnorm3d(cam_W, cam_W);
01831 
01832                 if (xformgradientsphere) {
01833                   rm.multnorm3d(scene_gradient, scene_gradient);
01834                 }
01835  
01836                 if (xformlights) {
01837                   // update light directions (comparatively costly)
01838                   for (i=0; i<directional_lights.num(); i++) {
01839                     rm.multnorm3d((float*)&cur_dlights[i].dir, (float*)&cur_dlights[i].dir);
01840                   }
01841                 }
01842 
01843                 winredraw = 1;
01844               } else if (mm == RTMM_TRANS) {
01845                 if (mousedown == RTMD_LEFT) {
01846                   float dU[3], dV[3];
01847                   vec_scale(dU, -txdx, cam_U);
01848                   vec_scale(dV,  txdy, cam_V);
01849                   vec_add(cam_pos, cam_pos, dU); 
01850                   vec_add(cam_pos, cam_pos, dV); 
01851                 } else if (mousedown == RTMD_MIDDLE || 
01852                            mousedown == RTMD_RIGHT) {
01853                   float dW[3];
01854                   vec_scale(dW, txdx, cam_W);
01855                   vec_add(cam_pos, cam_pos, dW); 
01856                 } 
01857                 winredraw = 1;
01858               } else if (mm == RTMM_SCALE) {
01859                 float txdx = (x - mousedownx) * 2.0 / wsx;
01860                 float zoominc = 1.0 - txdx;
01861                 if (zoominc < 0.01) zoominc = 0.01;
01862                 cam_zoom = cur_cam_zoom * zoominc;
01863                 winredraw = 1;
01864               } else if (mm == RTMM_DOF) {
01865                 cam_dof_fnumber += txdx * 20.0f;
01866                 if (cam_dof_fnumber < 1.0f) cam_dof_fnumber = 1.0f;
01867                 cam_dof_focal_dist += -txdy; 
01868                 if (cam_dof_focal_dist < 0.01f) cam_dof_focal_dist = 0.01f;
01869                 winredraw = 1;
01870               }
01871             }
01872             break;
01873 
01874           case GLWIN_EV_MOUSE_LEFT:
01875           case GLWIN_EV_MOUSE_MIDDLE:
01876           case GLWIN_EV_MOUSE_RIGHT:
01877             if (evval) {
01878               glwin_get_mousepointer(win, &mousedownx, &mousedowny);
01879               cur_cam_zoom = cam_zoom;
01880 
01881               if (evdev == GLWIN_EV_MOUSE_LEFT) mousedown = RTMD_LEFT;
01882               else if (evdev == GLWIN_EV_MOUSE_MIDDLE) mousedown = RTMD_MIDDLE;
01883               else if (evdev == GLWIN_EV_MOUSE_RIGHT) mousedown = RTMD_RIGHT;
01884             } else {
01885               mousedown = RTMD_NONE;
01886             }
01887             break;
01888 
01889           case GLWIN_EV_MOUSE_WHEELUP:
01890             cam_zoom /= 1.1f; winredraw = 1; break;
01891 
01892           case GLWIN_EV_MOUSE_WHEELDOWN:
01893             cam_zoom *= 1.1f; winredraw = 1; break;
01894         }
01895       }
01896     }
01897 
01898 
01899     //
01900     // Support for Spaceball/Spacenavigator/Magellan devices that use
01901     // X11 ClientMessage protocol....
01902     //
01903     //
01904     // Support for Spaceball/Spacenavigator/Magellan devices that use
01905     // X11 ClientMessage protocol....
01906     //
01907     if (spaceballenabled) {
01908       // Spaceball/Spacenavigator/Magellan event state variables
01909       int tx=0, ty=0, tz=0, rx=0, ry=0, rz=0, buttons=0;
01910       if (glwin_get_spaceball(win, &rx, &ry, &rz, &tx, &ty, &tz, &buttons)) {
01911         // negate directions if we're in flight mode...
01912         if (spaceballflightmode) {
01913           rx= -rx;
01914           ry= -ry;
01915           rz= -rz;
01916 
01917           tx= -tx;
01918           ty= -ty;
01919           tz= -tz;
01920         }
01921 
01922         // check for button presses to reset the view
01923         if (buttons & 1) {
01924           printf("ANARIRenderer) spaceball button 1 pressed: reset view\n");
01925           vec_copy(scene_gradient, scene_gradient_orig);
01926           cam_zoom = cam_zoom_orig;
01927           vec_copy(cam_pos, cam_pos_orig);
01928           vec_copy(cam_U, cam_U_orig);
01929           vec_copy(cam_V, cam_V_orig);
01930           vec_copy(cam_W, cam_W_orig);
01931 
01932           // restore original light directions
01933           for (i=0; i<directional_lights.num(); i++) {
01934             vec_copy((float*)&cur_dlights[i].dir, directional_lights[i].dir);
01935             vec_normalize((float*)&cur_dlights[i].dir);
01936           }
01937           winredraw = 1;
01938         }
01939 
01940         // check for button presses to toggle spaceball mode
01941         if (buttons & 2) {
01942           spaceballmode = !(spaceballmode);
01943           printf("ANARIRenderer) spaceball mode: %s                       \n",
01944                  (spaceballmode) ? "scaling" : "rotation/translation");
01945         }
01946 
01947         // rotation/translation mode
01948         if (spaceballmode == 0) {
01949           float zoommod = 2.0f*cam_zoom/cam_zoom_orig;
01950           float divlen = sqrtf(wsx*wsx + wsy*wsy) * 50;
01951 
01952           // check for rotation and handle it...
01953           if (rx != 0 || ry !=0 || rz !=0) {
01954             Matrix4 rm;
01955             rm.rotate_axis(cam_U, -rx * zoommod / divlen);
01956             rm.rotate_axis(cam_V, -ry * zoommod / divlen);
01957             rm.rotate_axis(cam_W, -rz * zoommod / divlen);
01958 
01959             rm.multpoint3d(cam_pos, cam_pos);
01960             rm.multnorm3d(cam_U, cam_U);
01961             rm.multnorm3d(cam_V, cam_V);
01962             rm.multnorm3d(cam_W, cam_W);
01963 
01964             if (xformgradientsphere) {
01965               rm.multnorm3d(scene_gradient, scene_gradient);
01966             }
01967 
01968             if (xformlights) {
01969               // update light directions (comparatively costly)
01970               for (i=0; i<directional_lights.num(); i++) {
01971                 rm.multnorm3d((float*)&cur_dlights[i].dir, (float*)&cur_dlights[i].dir);
01972               }
01973             }
01974             winredraw = 1;
01975           }
01976 
01977           // check for translation and handle it...
01978           if (tx != 0 || ty !=0 || tz !=0) {
01979             float dU[3], dV[3], dW[3];
01980             vec_scale(dU, -tx * zoommod / divlen, cam_U);
01981             vec_scale(dV, -ty * zoommod / divlen, cam_V);
01982             vec_scale(dW, -tz * zoommod / divlen, cam_W);
01983             vec_add(cam_pos, cam_pos, dU);
01984             vec_add(cam_pos, cam_pos, dV);
01985             vec_add(cam_pos, cam_pos, dW);
01986             winredraw = 1;
01987           }
01988         }
01989     
01990         // scaling mode
01991         if (spaceballmode == 1) {
01992           const float sbscale = 1.0f / (1024.0f * 8.0f);
01993           float zoominc = 1.0f - (rz * sbscale);
01994           if (zoominc < 0.01) zoominc = 0.01;
01995             cam_zoom *= zoominc;
01996             winredraw = 1;
01997         }
01998 
01999       }
02000     }
02001 
02002 
02003     // if there is no HMD, we use the camera orientation directly  
02004     vec_copy(hmd_U, cam_U);
02005     vec_copy(hmd_V, cam_V);
02006     vec_copy(hmd_W, cam_W);
02007 
02008     // XXX HMD handling goes here
02009 
02010     //
02011     // handle window resizing, stereoscopic mode changes,
02012     // destroy and recreate affected ANARI buffers
02013     //
02014     int resize_buffers=0;
02015 
02016     if (wsx != width) {
02017       width = wsx;
02018       resize_buffers=1;
02019     }
02020  
02021     if (wsy != height || (stereoon != stereoon_old)) {
02022       if (stereoon) {
02023         if (height != wsy * 2) {
02024           height = wsy * 2; 
02025           resize_buffers=1;
02026         }
02027       } else {
02028         height = wsy;
02029         resize_buffers=1;
02030       }
02031     }
02032 
02033 
02034     // check if stereo mode or DoF mode changed, both cases
02035     // require changing the active color accumulation ray gen program
02036     if ((stereoon != stereoon_old) || (gl_dof_on != gl_dof_on_old)) {
02037       // when stereo mode changes, we have to regenerate the
02038       // the RNG, accumulation buffer, and framebuffer
02039       if (stereoon != stereoon_old) {
02040         resize_buffers=1;
02041       }
02042 
02043       // update stereo and DoF state
02044       stereoon_old = stereoon;
02045       gl_dof_on_old = gl_dof_on;
02046 
02047       // set the active color accumulation ray gen mode based on the 
02048       // camera/projection mode, stereoscopic display mode, 
02049       // and depth-of-field state
02050       winredraw=1;
02051     }
02052 
02053     if (resize_buffers) {
02054       framebuffer_resize(width, height);
02055 
02056       // when movie recording is enabled, print the window size as a guide
02057       // since the user might want to precisely control the size or 
02058       // aspect ratio for a particular movie format, e.g. 1080p, 4:3, 16:9
02059       if (movie_recording_enabled) {
02060         printf("\rANARIRenderer) Window resize: %d x %d                               \n", width, height);
02061       }
02062 
02063       winredraw=1;
02064     }
02065 
02066     int frame_ready = 1; // Default to true
02067     unsigned int subframe_count = 1;
02068     if (!done) {
02069       //
02070       // If the user interacted with the window in a meaningful way, we
02071       // need to update the ANARI rendering state, recompile and re-validate
02072       // the context, and then re-render...
02073       //
02074       if (winredraw) {
02075         // update camera parameters
02076         anariSetParameter(dev, anariCamera, "position",  ANARI_FLOAT32_VEC3, cam_pos);
02077         anariSetParameter(dev, anariCamera, "direction", ANARI_FLOAT32_VEC3,   hmd_W);
02078         anariSetParameter(dev, anariCamera, "up",        ANARI_FLOAT32_VEC3,   hmd_V);
02079         float camaspect = width / ((float) height);
02080         anariSetParameter(dev, anariCamera, "aspect", ANARI_FLOAT32, &camaspect);
02081 
02082         float camfovy = 2.0f*180.0f*(atanf(cam_zoom)/M_PI);
02083         anariSetParameter(dev, anariCamera, "fovy", ANARI_FLOAT32, &camfovy);
02084  
02085         // update shadow state 
02086         // anariSetParameter(dev, anariRenderer, "shadowsEnabled", ANARI_INT32, &gl_shadows_on);
02087 
02088         // update AO state 
02089         if (gl_shadows_on && gl_ao_on) {
02090           const int one = 1;
02091           if (anari_rendermode == ANARI_SCIVIS)
02092             anariSetParameter(dev, anariRenderer, "aoSamples", ANARI_INT32, &one);
02093         } else {
02094           const int zero = 0;
02095           if (anari_rendermode == ANARI_SCIVIS)
02096             anariSetParameter(dev, anariRenderer, "aoSamples", ANARI_INT32, &zero);
02097         }
02098 
02099         // update depth cueing state
02100         // XXX update ANARI depth cueing state
02101  
02102         // update/recompute DoF values 
02103         // XXX ANARI only implements DoF for the perspective
02104         //     camera at the present time
02105         if (camera_projection == ANARIRender::RT_PERSPECTIVE) {
02106           if (gl_dof_on) {
02107             anariSetParameter(dev, anariCamera, "focusDistance", ANARI_FLOAT32, &cam_dof_focal_dist);
02108             float camaprad = cam_dof_focal_dist / (2.0f * cam_zoom * cam_dof_fnumber);
02109             anariSetParameter(dev, anariCamera, "apertureRadius", ANARI_FLOAT32, &camaprad);
02110           } else {
02111             float camaprad = 0.0f;
02112             anariSetParameter(dev, anariCamera, "apertureRadius", ANARI_FLOAT32, &camaprad);
02113           }
02114         }
02115 
02116         // commit camera updates once they're all done...
02117         anariCommit(dev, anariCamera);
02118 
02119         //
02120         // Update light directions in the ANARI light buffers
02121         //
02122         if (xformlights) {
02123           // AO scaling factor is applied at the renderer level, but
02124           // we apply the direct lighting scaling factor to the lights.
02125           float lightscale = 1.0f;
02126           if (ao_samples != 0)
02127             lightscale = ao_direct;
02128 
02129           // XXX assumes the only contents in the first part of the 
02130           //     light list are directional lights.  The new AO "ambient"
02131           //     light is the last light in the list now, so we can get
02132           //     away with this, but refactoring is still needed here.
02133           for (i=0; i<directional_lights.num(); i++) {
02134             anariSetParameter(dev, anariLights[i], "intensity", ANARI_FLOAT32, &lightscale);
02135             anariSetParameter(dev, anariLights[i], "color", ANARI_FLOAT32_VEC3, cur_dlights[i].color);
02136 
02137             float ltmp[3];
02138             vec_negate(ltmp, cur_dlights[i].dir);
02139             anariSetParameter(dev, anariLights[i], "direction", ANARI_FLOAT32_VEC3, ltmp);
02140             anariCommit(dev, anariLights[i]);
02141           }
02142         }
02143 
02144         // commit pending changes...
02145         anariCommit(dev, anariRenderer);
02146 
02147         // reset accumulation buffer 
02148         accum_count=0;
02149         totalsamplecount=0;
02150         if (anariFrameBuffer != NULL) {
02151 //          anariResetAccumulation(dev, anariFrameBuffer);
02152         }
02153 
02154         // 
02155         // Sample count updates and ANARI state must always remain in 
02156         // sync, so if we only update sample count state during redraw events,
02157         // that's the only time we should recompute the sample counts, since
02158         // they also affect normalization factors for the accumulation buffer
02159         //
02160 
02161         // Update sample counts to achieve target interactivity
02162         if (autosamplecount) {
02163           if (fpsexpave > 37)
02164             samples_per_pass++;
02165           else if (fpsexpave < 30) 
02166             samples_per_pass--;
02167     
02168           // clamp sample counts to a "safe" range
02169           if (samples_per_pass > 14)
02170             samples_per_pass=14;
02171           if (samples_per_pass < 1)
02172             samples_per_pass=1;
02173         } 
02174 
02175         // split samples per pass either among AA and AO, depending on
02176         // whether DoF and AO are enabled or not. 
02177         if (gl_shadows_on && gl_ao_on) {
02178           if (gl_dof_on) {
02179             if (samples_per_pass < 4) {
02180               cur_aa_samples=samples_per_pass;
02181               cur_ao_samples=1;
02182             } else {
02183               int s = (int) sqrtf(samples_per_pass);
02184               cur_aa_samples=s;
02185               cur_ao_samples=s;
02186             }
02187           } else {
02188             cur_aa_samples=1;
02189             cur_ao_samples=samples_per_pass;
02190           }
02191         } else {
02192           cur_aa_samples=samples_per_pass;
02193           cur_ao_samples=0;
02194         }
02195 
02196         // update the current AA/AO sample counts since they may be changing if
02197         // FPS autotuning is enabled...
02198         // XXX update ANARI AA sample counts
02199 
02200         // observe latest AO enable/disable flag, and sample count
02201         if (gl_shadows_on && gl_ao_on) {
02202           // XXX update ANARI AA/AO sample counts
02203         } else {
02204           cur_ao_samples = 0;
02205           // XXX update ANARI AA/AO sample counts
02206         }
02207       } 
02208 
02209 
02210       // The accumulation buffer normalization factor must be updated
02211       // to reflect the total accumulation count before the accumulation
02212       // buffer is drawn to the output framebuffer
02213       // XXX update ANARI accum buf normalization factor
02214 
02215       // The accumulation buffer subframe index must be updated to ensure that
02216       // the RNGs for AA and AO get correctly re-seeded
02217       // XXX update ANARI accum subframe count
02218 
02219       // Force context compilation/validation
02220       // render_compile_and_validate();
02221 
02222       anariSetParameter(dev, anariFrameBuffer, "renderer", ANARI_RENDERER, &anariRenderer);
02223       anariSetParameter(dev, anariFrameBuffer, "camera", ANARI_CAMERA, &anariCamera);
02224       anariSetParameter(dev, anariFrameBuffer, "world", ANARI_WORLD, &anariWorld);
02225       anariCommit(dev, anariFrameBuffer);
02226 
02227 
02228       //
02229       // run the renderer 
02230       //
02231       frame_ready = 1; // Default to true
02232       subframe_count = 1;
02233       if (lasterror == 0 /* XXX SUCCESS */) {
02234         if (winredraw) {
02235 //          anariResetAccumulation(dev, anariFrameBuffer);
02236           winredraw=0;
02237         }
02238 
02239         // iterate, adding to the accumulation buffer...
02240         anariRenderFrame(dev, anariFrameBuffer);
02241         anariFrameReady(dev, anariFrameBuffer, ANARI_WAIT);
02242 
02243         subframe_count++; // increment subframe index
02244         totalsamplecount += samples_per_pass;
02245         accum_count += cur_aa_samples;
02246 
02247         // copy the accumulation buffer image data to the framebuffer and
02248         // perform type conversion and normaliztion on the image data...
02249         // XXX launch ANARI accum copy/norm/finish
02250 
02251         if (lasterror == 0 /* XXX SUCCESS */) {
02252           if (frame_ready) {
02253             // display output image
02254             const unsigned char * img;
02255             img = (const unsigned char*)anariMapFrame(dev, anariFrameBuffer, "color");
02256 
02257 #if 0
02258             glwin_draw_image_tex_rgb3u(win, (stereoon!=0)*GLWIN_STEREO_OVERUNDER, width, height, img);
02259 #else
02260             glwin_draw_image_rgb3u(win, (stereoon!=0)*GLWIN_STEREO_OVERUNDER, width, height, img);
02261 #endif
02262             anariUnmapFrame(dev, anariFrameBuffer, "color");
02263 
02264             // if live movie recording is on, we save every displayed frame
02265             // to a sequence sequence of image files, with each file numbered
02266             // by its frame index, which is computed by the multiplying image
02267             // presentation time by the image sequence fixed-rate-FPS value.
02268             if (movie_recording_enabled && movie_recording_on) {
02269               char moviefilename[2048];
02270 
02271               // compute frame number from wall clock time and the
02272               // current fixed-rate movie playback frame rate
02273               double now = wkf_timer_timenow(anr_timer);
02274               double frametime = now - movie_recording_start_time;
02275               int fidx = frametime * movie_recording_fps;
02276 
02277               // always force the first recorded frame to be 0
02278               if (movie_framecount==0)
02279                 fidx=0;
02280               movie_framecount++;
02281 
02282 #if defined(__linux)
02283               // generate symlinks for frame indices between the last written
02284               // frame and the current one so that video encoders such as
02285               // ffmpeg and mencoder can be fed the contiguous frame sequence
02286               // at a fixed frame rate, as they require
02287               sprintf(moviefilename, movie_recording_filebase,
02288                       movie_lastframeindex);
02289               int symidx;
02290               for (symidx=movie_lastframeindex; symidx<fidx; symidx++) {
02291                 char symlinkfilename[2048];
02292                 sprintf(symlinkfilename, movie_recording_filebase, symidx);
02293                 symlink(moviefilename, symlinkfilename);
02294               }
02295 #endif
02296 
02297               // write the new movie frame
02298               sprintf(moviefilename, movie_recording_filebase, fidx);
02299               const unsigned char *FB = (const unsigned char*)anariMapFrame(dev, anariFrameBuffer, "color");
02300               if (write_image_file_rgb4u(moviefilename, FB, width, height)) {
02301                 movie_recording_on = 0;
02302                 printf("\n");
02303                 printf("ANARIRenderer) ERROR during writing image during movie recording!\n");
02304                 printf("ANARIRenderer) Movie recording STOPPED\n");
02305               }
02306               anariUnmapFrame(dev, anariFrameBuffer, "color");
02307 
02308               movie_lastframeindex = fidx; // update last frame index written
02309             }
02310           }
02311         } else {
02312           printf("ANARIRenderer) An error occured during rendering. Rendering is aborted.\n");
02313           done=1;
02314           break;
02315         }
02316       } else {
02317         printf("ANARIRenderer) An error occured in AS generation. Rendering is aborted.\n");
02318         done=1;
02319         break;
02320       }
02321     }
02322 
02323     if (!done && frame_ready) {
02324       double newtime = wkf_timer_timenow(anr_timer);
02325       double frametime = (newtime-oldtime) + 0.00001f;
02326       oldtime=newtime;
02327 
02328       // compute exponential moving average for exp(-1/10)
02329       double framefps = 1.0f/frametime;
02330       fpsexpave = (fpsexpave * 0.90) + (framefps * 0.10);
02331 
02332       printf("ANARIRenderer) %c AA:%2d AO:%2d, %4d tot RT FPS: %.1f  %.4f s/frame sf: %d  \r",
02333              statestr[state], cur_aa_samples, cur_ao_samples, 
02334              totalsamplecount, fpsexpave, frametime, subframe_count);
02335 
02336       fflush(stdout);
02337       state = (state+1) & 3;
02338     }
02339 
02340   } // end of per-cycle event processing
02341 
02342   printf("\n");
02343 
02344   // write the output image upon exit...
02345   if (lasterror == 0 /* XXX SUCCESS */) {
02346     wkf_timer_start(anr_timer);
02347     // write output image
02348     const unsigned char *FB = (const unsigned char*)anariMapFrame(dev, anariFrameBuffer, "color");
02349     if (write_image_file_rgb4u(filename, FB, width, height)) {
02350       printf("ANARIRenderer) Failed to write output image!\n");
02351     }
02352     anariUnmapFrame(dev, anariFrameBuffer, "color");
02353     wkf_timer_stop(anr_timer);
02354 
02355     if (verbose == RT_VERB_TIMING || verbose == RT_VERB_DEBUG) {
02356       printf("ANARIRenderer) image file I/O time: %f secs\n", wkf_timer_time(anr_timer));
02357     }
02358   }
02359 
02360   glwin_destroy(win);
02361 }
02362 
02363 #endif
02364 
02365 
02366 void ANARIRender::render_to_file(const char *filename) {
02367   DBG();
02368   if (!context_created)
02369     return;
02370 
02371   // Unless overridden by environment variables, we use the incoming
02372   // window size parameters from VMD to initialize the RT image dimensions.
02373   int wsx=width, wsy=height;
02374   const char *imageszstr = getenv("VMDANARIIMAGESIZE");
02375   if (imageszstr) {
02376     if (sscanf(imageszstr, "%d %d", &width, &height) != 2) {
02377       width=wsx;
02378       height=wsy;
02379     } 
02380   } 
02381 
02382   // config/allocate framebuffer and accumulation buffer
02383   framebuffer_config(width, height);
02384 
02385   update_rendering_state(0);
02386   render_compile_and_validate();
02387   double starttime = wkf_timer_timenow(anr_timer);
02388 
02389   // XXX extra world commit for the benefit of USD...
02390   if (rendererworkarounds == ANARI_USD) {
02391     printf("ANARIRenderer) *** extra anariWorld commit for USD...\n");
02392     anariCommit(dev, anariWorld);
02393   }
02394 
02395 
02396   //
02397   // XXX for ANARI we currently defer FB setup to just before rendering, 
02398   //     because the frame object serves as our main sync point and
02399   //     we have to have already committed our renderer, camera, world, etc,
02400   //     prior to committing the frame for the call to anariRenderFrame().
02401   // 
02402 
02403 
02404   anariFrameBuffer = anariNewFrame(dev);
02405   int imgsz[2];
02406   imgsz[0] = width;
02407   imgsz[1] = height;
02408   anariSetParameter(dev, anariFrameBuffer, "size", ANARI_UINT32_VEC2, &imgsz);
02409 
02410   // create intermediate output and accumulation buffers
02411   // One of: UFIXED8_VEC4, UFIXED8_RGBA_SRGB, FLOAT32_VEC4
02412 //  ANARIDataType format = ANARI_UFIXED8_RGBA_SRGB;
02413   ANARIDataType format = ANARI_UFIXED8_VEC4;
02414   anariSetParameter(dev, anariFrameBuffer, "color", ANARI_DATA_TYPE, &format);
02415 
02416   anariSetParameter(dev, anariFrameBuffer, "renderer", ANARI_RENDERER, &anariRenderer);
02417   anariSetParameter(dev, anariFrameBuffer, "camera", ANARI_CAMERA, &anariCamera);
02418   anariSetParameter(dev, anariFrameBuffer, "world", ANARI_WORLD, &anariWorld);
02419   anariCommit(dev, anariFrameBuffer);
02420 
02421 
02422   //
02423   // run the renderer 
02424   //
02425   if (lasterror == 0 /* XXX SUCCESS */) {
02426     // clear the accumulation buffer
02427 //    anariResetAccumulation(dev, anariFrameBuffer);
02428 
02429     // Render to the accumulation buffer for the required number of passes
02430     if (getenv("VMDANARINORENDER") == NULL) {
02431       if (rendererworkarounds == ANARI_USD) {
02432         anariRenderFrame(dev, anariFrameBuffer);
02433         anariFrameReady(dev, anariFrameBuffer, ANARI_WAIT);
02434       } else {
02435         int accum_sample;
02436         for (accum_sample=0; accum_sample<ext_aa_loops; accum_sample++) {
02437           // The accumulation subframe count must be updated to ensure that
02438           // any custom RNGs for AA and AO get correctly re-seeded
02439           anariRenderFrame(dev, anariFrameBuffer);
02440           anariFrameReady(dev, anariFrameBuffer, ANARI_WAIT);
02441         }
02442       }
02443     }
02444 
02445     // copy the accumulation buffer image data to the framebuffer and perform
02446     // type conversion and normaliztion on the image data...
02447     double rtendtime = wkf_timer_timenow(anr_timer);
02448     time_ray_tracing = rtendtime - starttime;
02449 
02450     if (rendererworkarounds != ANARI_USD) {
02451       if (lasterror == 0 /* XXX SUCCESS */) {
02452         // write output image to a file unless we are benchmarking
02453         if (getenv("VMDANARINOSAVE") == NULL) {
02454           const unsigned char *FB = (const unsigned char*)anariMapFrame(dev, anariFrameBuffer, "color");
02455           if (write_image_file_rgb4u(filename, FB, width, height)) {
02456             printf("ANARIRenderer) Failed to write output image!\n");
02457           }
02458           anariUnmapFrame(dev, anariFrameBuffer, "color");
02459         }
02460         time_image_io = wkf_timer_timenow(anr_timer) - rtendtime;
02461       } else {
02462         printf("ANARIRenderer) Error during rendering.  Rendering aborted.\n");
02463       }
02464     }
02465 
02466     if (verbose == RT_VERB_TIMING || verbose == RT_VERB_DEBUG) {
02467       printf("ANARIRenderer) 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);
02468     }
02469   } else {
02470     printf("ANARIRenderer) Error during AS generation.  Rendering aborted.\n");
02471   }
02472 }
02473 
02474 
02475 void ANARIRender::add_material(int matindex,
02476                                float ambient, float diffuse, 
02477                                float specular,
02478                                float shininess, float reflectivity,
02479                                float opacity, 
02480                                float outline, float outlinewidth,
02481                                int transmode) {
02482 if (dev == NULL) {
02483   printf("add_material() ANARI device is NULL!!!\n");
02484   return;
02485 }
02486   
02487 
02488 printf("ANARI Add mat[%d]\n", matindex);
02489   int oldmatcount = materialcache.num();
02490   if (oldmatcount <= matindex) {
02491     anr_material m;
02492     memset(&m, 0, sizeof(m));
02493 
02494     // XXX do something noticable so we see that we got a bad entry...
02495     m.ambient = 0.5f;
02496     m.diffuse = 0.7f;
02497     m.specular = 0.0f;
02498     m.shininess = 10.0f;
02499     m.reflectivity = 0.0f;
02500     m.opacity = 1.0f;
02501     m.transmode = 0;
02502 
02503     materialcache.appendN(m, matindex - oldmatcount + 1);
02504   }
02505  
02506   if (materialcache[matindex].isvalid) {
02507     return;
02508   } else {
02509     if (verbose == RT_VERB_DEBUG) printf("ANARIRenderer) Adding material[%d]\n", matindex);
02510 
02511     materialcache[matindex].ambient      = ambient;
02512     materialcache[matindex].diffuse      = diffuse; 
02513     materialcache[matindex].specular     = specular;
02514     materialcache[matindex].shininess    = shininess;
02515     materialcache[matindex].reflectivity = reflectivity;
02516     materialcache[matindex].opacity      = opacity;
02517     materialcache[matindex].outline      = outline;
02518     materialcache[matindex].outlinewidth = outlinewidth;
02519     materialcache[matindex].transmode    = transmode;
02520 
02521     // create an ANARI material object too...
02522     float mtmp[3];
02523     ANARIMaterial anariMat;
02524 
02525     if (rendererworkarounds == ANARI_USD) {
02526       anari_matclass = ANARI_MATTE;
02527     }
02528 
02529 
02530     // choose the right material depending on the active material class
02531     // and selected renderer type
02532     switch (anari_matclass) {
02533       case ANARI_MATTE: 
02534         {
02535           if (opacity < 1.0f) {
02536             // partial cut-out transparency
02537             anariMat = anariNewMaterial(dev, "transparentMatte");
02538           } else {
02539             anariMat = anariNewMaterial(dev, "matte");
02540           }
02541 
02542           mtmp[0] = mtmp[1] = mtmp[2] = materialcache[matindex].diffuse;
02543           anariSetParameter(dev, anariMat, "kd", ANARI_FLOAT32_VEC3, mtmp);
02544           anariSetParameter(dev, anariMat, "d", ANARI_FLOAT32, &materialcache[matindex].opacity);
02545         }
02546         break;
02547 
02548       default:
02549       case ANARI_OBJ: 
02550         {
02551           anariMat = anariNewMaterial(dev, "obj");
02552 
02553           mtmp[0] = mtmp[1] = mtmp[2] = materialcache[matindex].diffuse;
02554           anariSetParameter(dev, anariMat, "kd", ANARI_FLOAT32_VEC3, mtmp);
02555           anariSetParameter(dev, anariMat, "d", ANARI_FLOAT32, &materialcache[matindex].opacity);
02556 
02557           mtmp[0] = mtmp[1] = mtmp[2] = materialcache[matindex].specular;
02558           anariSetParameter(dev, anariMat, "ks", ANARI_FLOAT32_VEC3, mtmp);
02559 
02560           anariSetParameter(dev, anariMat, "ns", ANARI_FLOAT32, &materialcache[matindex].shininess);
02561         }
02562         break;
02563     }
02564 
02565 
02566     if (rendererworkarounds == ANARI_USD) {
02567       int usetrue = 1;
02568       anariSetParameter(dev, anariMat, "usevertexcolors", ANARI_BOOL, &usetrue);
02569 
02570       // if using the USD back-end, assign the "name" tag for the material...
02571       if (rendererworkarounds == ANARI_USD && (strlen(lastcommentstring) > 0)) {
02572         char strbuf[2048];
02573         sprintf(strbuf, "VMD material %d", matindex);
02574         anariSetParameter(dev, anariMat, "name", ANARI_STRING, strbuf);
02575       }
02576     }
02577 
02578     anariCommit(dev, anariMat);
02579     materialcache[matindex].mat = anariMat;
02580     materialcache[matindex].isvalid      = 1;
02581   }
02582 }
02583 
02584 
02585 // record the most recent comment token for use by ANARI object "name" tags
02586 void ANARIRender::comment(const char *s) {
02587   commit_rep();  
02588 
02589   printf("ANARIRenderer) comment: '%s'\n", s);
02590   strncpy(lastcommentstring, s, sizeof(lastcommentstring) - 1);
02591   lastcommentstring[sizeof(lastcommentstring)-1] = '\0';
02592 }
02593 
02594 
02595 void ANARIRender::init_materials() {
02596   DBG();
02597   if (verbose == RT_VERB_DEBUG) printf("ANARIRenderer) init_materials()\n");
02598 
02599   materialcache.clear();
02600 }
02601 
02602 
02603 void ANARIRender::set_material(ANARISurface &surf, int matindex, float *uniform_color) {
02604   if (!context_created)
02605     return;
02606 
02607   if (verbose == RT_VERB_DEBUG) 
02608     printf("ANARIRenderer)   setting material %d\n", matindex);
02609   anariSetParameter(dev, surf, "material", ANARI_MATERIAL, &materialcache[matindex].mat);
02610 }
02611 
02612 
02613 void ANARIRender::attach_mesh(int numverts, int numfacets, int matindex,
02614                               anr_trimesh_v3f_n3f_c3f &mesh) {
02615   mesh.matindex = matindex;
02616   mesh.verts = anariNewArray1D(dev, mesh.v, 0, 0, ANARI_FLOAT32_VEC3, numverts, 0);
02617   anariCommit(dev, mesh.verts);
02618   mesh.norms = anariNewArray1D(dev, mesh.n, 0, 0, ANARI_FLOAT32_VEC3, numverts, 0);
02619   anariCommit(dev, mesh.norms);
02620   mesh.cols  = anariNewArray1D(dev, mesh.c, 0, 0, ANARI_FLOAT32_VEC4, numverts, 0);
02621   anariCommit(dev, mesh.cols);
02622   mesh.ind   = anariNewArray1D(dev, mesh.f, 0, 0, ANARI_UINT32_VEC3, numfacets, 0);
02623   anariCommit(dev, mesh.ind);
02624 
02625   mesh.geom  = anariNewGeometry(dev, "triangle");
02626 
02627   anariSetParameter(dev, mesh.geom, "vertex.position", ANARI_ARRAY1D, &mesh.verts);
02628   anariRelease(dev, mesh.verts);
02629 
02630   anariSetParameter(dev, mesh.geom, "vertex.normal",   ANARI_ARRAY1D, &mesh.norms);
02631   anariRelease(dev, mesh.norms);
02632 
02633   anariSetParameter(dev, mesh.geom, "primitive.index", ANARI_ARRAY1D, &mesh.ind);
02634   anariRelease(dev, mesh.ind);
02635 
02636   anariSetParameter(dev, mesh.geom, "vertex.color",    ANARI_ARRAY1D, &mesh.cols);
02637   anariRelease(dev, mesh.cols);
02638 
02639   anariCommit(dev, mesh.geom);
02640 
02641   mesh.surf = anariNewSurface(dev); 
02642   anariSetParameter(dev, mesh.surf, "geometry", ANARI_GEOMETRY, &mesh.geom);
02643   set_material(mesh.surf, matindex, NULL);
02644 
02645   anariCommit(dev, mesh.surf);
02646   anariRelease(dev, mesh.geom);
02647   trimesh_v3f_n3f_c3f.append(mesh); 
02648 }
02649 
02650 
02651 void ANARIRender::attach_sphere_array(int numsp, int matindex,
02652                                       anr_sphere_array_color &sparray) {
02653   sparray.matindex = matindex;
02654 
02655   sparray.cents = anariNewArray1D(dev, sparray.xyz, 0, 0, ANARI_FLOAT32_VEC3, numsp, 0);
02656   anariCommit(dev, sparray.cents);
02657   sparray.rads = anariNewArray1D(dev, sparray.radii, 0, 0, ANARI_FLOAT32, numsp, 0);
02658   anariCommit(dev, sparray.rads);
02659   sparray.cols = anariNewArray1D(dev, sparray.colors, 0, 0, ANARI_FLOAT32_VEC4, numsp, 0);
02660   anariCommit(dev, sparray.cols);
02661 
02662   sparray.geom  = anariNewGeometry(dev, "sphere");
02663   anariSetParameter(dev, sparray.geom, "vertex.position", ANARI_ARRAY1D, &sparray.cents);
02664   anariSetParameter(dev, sparray.geom, "vertex.radius",   ANARI_ARRAY1D, &sparray.rads);
02665   anariSetParameter(dev, sparray.geom, "vertex.color", ANARI_ARRAY1D, &sparray.cols);
02666   anariCommit(dev, sparray.geom);
02667   anariRelease(dev, sparray.cents);
02668   anariRelease(dev, sparray.rads);
02669   anariRelease(dev, sparray.cols);
02670 
02671   sparray.surf = anariNewSurface(dev);
02672   anariSetParameter(dev, sparray.surf, "geometry", ANARI_GEOMETRY, &sparray.geom);
02673   set_material(sparray.surf, matindex, NULL);
02674   anariCommit(dev, sparray.surf);
02675   anariRelease(dev, sparray.geom);
02676 
02677   spheres_color.append(sparray);
02678 }
02679 
02680 
02681 void ANARIRender::attach_cylinder_array(int numcyl, int matindex,
02682                                         anr_cylinder_array_color &cylarray) {
02683   cylarray.matindex = matindex;
02684   cylarray.cyls = anariNewArray1D(dev, cylarray.verts, 0, 0, ANARI_FLOAT32_VEC3, numcyl * 2, 0);
02685   anariCommit(dev, cylarray.cyls);
02686   cylarray.rads = anariNewArray1D(dev, cylarray.radii, 0, 0, ANARI_FLOAT32, numcyl, 0);
02687   anariCommit(dev, cylarray.rads);
02688   cylarray.cols = anariNewArray1D(dev, cylarray.colors, 0, 0, ANARI_FLOAT32_VEC4, numcyl, 0);
02689   anariCommit(dev, cylarray.cols);
02690   cylarray.ind  = anariNewArray1D(dev, cylarray.indices, 0, 0, ANARI_UINT32, numcyl * 1, 0);
02691   anariCommit(dev, cylarray.ind);
02692 
02693   cylarray.geom  = anariNewGeometry(dev, "curve");
02694   anariSetParameter(dev, cylarray.geom, "vertex.position", ANARI_ARRAY1D, &cylarray.cyls);
02695   anariSetParameter(dev, cylarray.geom, "vertex.radius",   ANARI_ARRAY1D, &cylarray.rads);
02696   anariSetParameter(dev, cylarray.geom, "vertex.index",    ANARI_ARRAY1D, &cylarray.ind);
02697 
02698   cylarray.surf = anariNewSurface(dev);
02699   anariSetParameter(dev, cylarray.surf, "geometry", ANARI_GEOMETRY, &cylarray.geom);
02700   anariSetParameter(dev, cylarray.surf, "primitive.color", ANARI_ARRAY1D, &cylarray.cols);
02701   set_material(cylarray.surf, matindex, NULL);
02702   anariCommit(dev, cylarray.surf);
02703   anariRelease(dev, cylarray.geom);
02704 
02705   free(cylarray.cyls);
02706   cylarray.cyls = NULL;
02707   free(cylarray.rads);
02708   cylarray.rads = NULL;
02709   free(cylarray.ind);
02710   cylarray.ind = NULL;
02711   free(cylarray.cols);
02712   cylarray.cols = NULL;
02713 
02714   cylinders_color.append(cylarray);
02715 }
02716 
02717 
02718 
02719 void ANARIRender::add_directional_light(const float *dir, const float *color) {
02720   DBG();
02721   anr_directional_light l;
02722   vec_copy(l.dir, dir);
02723   vec_copy(l.color, color);
02724 
02725   directional_lights.append(l);
02726 }
02727 
02728 
02729 void ANARIRender::add_positional_light(const float *pos, const float *color) {
02730   DBG();
02731   anr_positional_light l;
02732   vec_copy(l.pos, pos);
02733   vec_copy(l.color, color);
02734 
02735   positional_lights.append(l);
02736 }
02737 
02738 
02739 void ANARIRender::cylinder_array(Matrix4 *wtrans, float radius,
02740                                  float *uniform_color,
02741                                  int cylnum, float *points, int matindex) {
02742   DBG();
02743   if (!context_created) return;
02744   if (verbose == RT_VERB_DEBUG) printf("ANARIRenderer) creating cylinder array: %d...\n", cylnum);
02745 
02746   cylinder_array_cnt += cylnum;
02747   
02748   anr_cylinder_array_color ca;
02749   memset(&ca, 0, sizeof(ca));
02750   ca.num = cylnum;
02751   ca.verts = (float *) calloc(1, cylnum * 6 * sizeof(float));
02752   ca.radii = (float *) calloc(1, cylnum * 1 * sizeof(float));
02753   ca.colors = (float *) calloc(1, cylnum * 4 * sizeof(float));
02754   ca.indices = (unsigned int *) calloc(1, cylnum * 2 * sizeof(unsigned int));
02755 
02756   int i,ind4,ind6;
02757   if (wtrans == NULL) {
02758     for (i=0,ind4=0,ind6=0; i<cylnum; i++,ind4+=4,ind6+=6) {
02759       vec_copy(&ca.verts[ind6  ], &points[ind6  ]);
02760       vec_copy(&ca.verts[ind6+3], &points[ind6+3]);
02761       ca.radii[i] = radius;
02762       vec_copy(&ca.colors[ind4], &uniform_color[0]);
02763       ca.colors[ind4 + 3] = 1.0f;
02764       ca.indices[i] = i*2;
02765     }
02766   } else {
02767     for (i=0,ind4=0,ind6=0; i<cylnum; i++,ind4+=4,ind6+=6) {
02768       // apply transforms on points, radii
02769       wtrans->multpoint3d(&points[ind6  ], &ca.verts[ind6  ]);
02770       wtrans->multpoint3d(&points[ind6+3], &ca.verts[ind6+3]);
02771       ca.radii[i] = radius;
02772       vec_copy(&ca.colors[ind4], &uniform_color[0]);
02773       ca.colors[ind4 + 3] = 1.0f;
02774       ca.indices[i] = i*2;
02775     }
02776   }
02777 
02778   attach_cylinder_array(cylnum, matindex, ca);
02779 }
02780 
02781 
02782 void ANARIRender::cylinder_array_color(Matrix4 & wtrans, float rscale,
02783                                        int cylnum, float *points,
02784                                        float *radii, float *colors,
02785                                        int matindex) {
02786   DBG();
02787   if (!context_created) return;
02788   if (verbose == RT_VERB_DEBUG) printf("ANARIRenderer) creating color cylinder array: %d...\n", cylnum);
02789   cylinder_array_color_cnt += cylnum;
02790 
02791   anr_cylinder_array_color cac;
02792   memset(&cac, 0, sizeof(cac));
02793   cac.num = cylnum;
02794   cac.verts = (float *) calloc(1, cylnum * 6 * sizeof(float));
02795   cac.radii = (float *) calloc(1, cylnum * 1 * sizeof(float));
02796   cac.colors = (float *) calloc(1, cylnum * 4 * sizeof(float));
02797   cac.indices = (unsigned int *) calloc(1, cylnum * 2 * sizeof(unsigned int));
02798 
02799   int i, ind3, ind4, ind6;
02800   for (i=0,ind3=0,ind4=0,ind6=0; i<cylnum; i++,ind3+=3,ind4+=4,ind6+=6) {
02801     // apply transforms on points, radii
02802     wtrans.multpoint3d(&points[ind6  ], &cac.verts[ind6  ]);
02803     wtrans.multpoint3d(&points[ind6+3], &cac.verts[ind6+3]);
02804     cac.radii[i] = radii[i] * rscale; // radius
02805     vec_copy(&cac.colors[ind4], &colors[ind3]);
02806     cac.colors[ind4 + 3] = 1.0f;
02807     cac.indices[i] = i*2;
02808   }
02809 
02810   attach_cylinder_array(cylnum, matindex, cac);
02811 }
02812 
02813 #if 0
02814 void ANARIRender::ring_array_color(Matrix4 & wtrans, float rscale,
02815                                    int rnum, float *centers,
02816                                    float *norms, float *radii, 
02817                                    float *colors, int matindex) {
02818 }
02819 #endif
02820 
02821 
02822 void ANARIRender::sphere_array(Matrix4 *wtrans, float rscale,
02823                                float *uniform_color,
02824                                int numsp, float *centers,
02825                                float *radii,
02826                                int matindex) {
02827   DBG();
02828   if (!context_created) return;
02829   if (verbose == RT_VERB_DEBUG) printf("ANARIRenderer) creating sphere array: %d...\n", numsp);
02830   sphere_array_cnt += numsp;
02831 
02832   const rgba c = { uniform_color[0], uniform_color[1], uniform_color[2], 1.0f};
02833 
02834   anr_sphere_array_color sp;
02835   memset(&sp, 0, sizeof(sp));
02836   sp.num = numsp;
02837   sp.xyz = (float *) calloc(1, numsp * 3*sizeof(float));
02838   sp.radii = (float *) calloc(1, numsp * sizeof(float));
02839   sp.colors = (float *) calloc(1, numsp * 4*sizeof(float));
02840 
02841   int i, ind3, ind4;
02842   if (wtrans == NULL) {
02843     if (radii == NULL) {
02844       for (i=0,ind3=0,ind4=0; i<numsp; i++,ind3+=3,ind4+=4) {
02845         // transform to eye coordinates
02846         vec_copy((float*) &sp.xyz[ind3], &centers[ind3]);
02847         sp.radii[i] = rscale;
02848         memcpy((float*) &sp.colors[ind4], &c, 4*sizeof(float));
02849       }
02850     } else {
02851       for (i=0,ind3=0,ind4=0; i<numsp; i++,ind3+=3,ind4+=4) {
02852         // transform to eye coordinates
02853         vec_copy((float*) &sp.xyz[ind3], &centers[ind3]);
02854         sp.radii[i] = radii[i] * rscale;
02855         memcpy((float*) &sp.colors[ind4], &c, 4*sizeof(float));
02856       }
02857     }
02858   } else {
02859     if (radii == NULL) {
02860       for (i=0,ind3=0,ind4=0; i<numsp; i++,ind3+=3,ind4+=4) {
02861         wtrans->multpoint3d(&centers[ind3], &sp.xyz[ind3]);
02862         sp.radii[i] = rscale;
02863         memcpy((float*) &sp.colors[ind4], &c, 4*sizeof(float));
02864       }
02865     } else {
02866       for (i=0,ind3=0,ind4=0; i<numsp; i++,ind3+=3,ind4+=4) {
02867         // transform to eye coordinates
02868         wtrans->multpoint3d(&centers[ind3], &sp.xyz[ind3]);
02869         sp.radii[i] = radii[i] * rscale;
02870         memcpy((float*) &sp.colors[ind4], &c, 4*sizeof(float));
02871       }
02872     }
02873   }
02874 
02875   attach_sphere_array(numsp, matindex, sp);
02876 }
02877 
02878 
02879 void ANARIRender::sphere_array_color(Matrix4 & wtrans, float rscale,
02880                                      int numsp, float *centers,
02881                                      float *radii, float *colors,
02882                                      int matindex) {
02883   DBG();
02884   if (!context_created) return;
02885   if (verbose == RT_VERB_DEBUG) printf("ANARIRenderer) creating sphere array color: %d...\n", numsp);
02886   sphere_array_color_cnt += numsp;
02887 
02888   anr_sphere_array_color sp;
02889   memset(&sp, 0, sizeof(sp));
02890   sp.num = numsp;
02891   sp.xyz = (float *) calloc(1, numsp * 3*sizeof(float));
02892   sp.radii = (float *) calloc(1, numsp * sizeof(float));
02893   sp.colors = (float *) calloc(1, numsp * 4*sizeof(float));
02894 
02895   int i, ind3, ind4;
02896   for (i=0,ind3=0,ind4=0; i<numsp; i++,ind3+=3,ind4+=4) {
02897     wtrans.multpoint3d(&centers[ind3], &sp.xyz[ind3]);
02898     sp.radii[i] = radii[i] * rscale;
02899     vec_copy((float*) &sp.colors[ind4], &colors[ind3]);
02900     sp.colors[ind4 + 3] = 1.0f;
02901   }
02902 
02903   attach_sphere_array(numsp, matindex, sp);
02904 }
02905 
02906 
02907 void ANARIRender::tricolor_list(Matrix4 & wtrans, int numtris, float *vnc,
02908                                 int matindex) {
02909   if (!context_created) return;
02910 //if (verbose == RT_VERB_DEBUG) printf("ANARIRenderer) creating tricolor list: %d...\n", numtris);
02911   tricolor_cnt += numtris;
02912 
02913   // create and fill the ANARI trimesh memory buffer
02914   anr_trimesh_v3f_n3f_c3f mesh;
02915   memset(&mesh, 0, sizeof(mesh));
02916   mesh.num = numtris;
02917   mesh.v = (float *) calloc(1, numtris * 9*sizeof(float));
02918   mesh.n = (float *) calloc(1, numtris * 9*sizeof(float));
02919   mesh.c = (float *) calloc(1, numtris * 12*sizeof(float));
02920   mesh.f = (int *) calloc(1, numtris * 3*sizeof(int));
02921   
02922   float alpha = 1.0f;
02923 //  alpha = materialcache[matindex].opacity;
02924 
02925   int i, ind, ind9, ind12;
02926   for (i=0,ind=0,ind9=0,ind12=0; i<numtris; i++,ind+=27,ind9+=9,ind12+=12) {
02927     // transform to eye coordinates
02928     wtrans.multpoint3d(&vnc[ind    ], (float*) &mesh.v[ind9    ]);
02929     wtrans.multpoint3d(&vnc[ind + 3], (float*) &mesh.v[ind9 + 3]);
02930     wtrans.multpoint3d(&vnc[ind + 6], (float*) &mesh.v[ind9 + 6]);
02931 
02932     wtrans.multnorm3d(&vnc[ind +  9], (float*) &mesh.n[ind9    ]);
02933     wtrans.multnorm3d(&vnc[ind + 12], (float*) &mesh.n[ind9 + 3]);
02934     wtrans.multnorm3d(&vnc[ind + 15], (float*) &mesh.n[ind9 + 6]);
02935 
02936     vec_copy(&mesh.c[ind12    ], &vnc[ind + 18]);
02937     mesh.c[ind12 +  3] = alpha;
02938     vec_copy(&mesh.c[ind12 + 4], &vnc[ind + 21]);
02939     mesh.c[ind12 +  7] = alpha;
02940     vec_copy(&mesh.c[ind12 + 8], &vnc[ind + 24]);
02941     mesh.c[ind12 + 11] = alpha;
02942 
02943     mesh.f[i*3  ] = i*3;
02944     mesh.f[i*3+1] = i*3 + 1;
02945     mesh.f[i*3+2] = i*3 + 2;
02946   }
02947 
02948   attach_mesh(numtris * 3, numtris, matindex, mesh);
02949 }
02950 
02951 
02952 void ANARIRender::trimesh_c4n3v3(Matrix4 & wtrans, int numverts,
02953                                  float *cnv, int numfacets, int * facets,
02954                                  int matindex) {
02955   if (!context_created) return;
02956   if (verbose == RT_VERB_DEBUG) printf("ANARIRenderer) creating trimesh_c4n3v3: %d...\n", numfacets);
02957   trimesh_c4u_n3b_v3f_cnt += numfacets;
02958 
02959   // create and fill the ANARI trimesh memory buffer
02960   anr_trimesh_v3f_n3f_c3f mesh;
02961   memset(&mesh, 0, sizeof(mesh));
02962   mesh.num = numfacets;
02963   mesh.v = (float *) calloc(1, numfacets * 9*sizeof(float));
02964   mesh.n = (float *) calloc(1, numfacets * 9*sizeof(float));
02965   mesh.c = (float *) calloc(1, numfacets * 12*sizeof(float));
02966   mesh.f = (int *) calloc(1, numfacets * 3*sizeof(int));
02967  
02968   float alpha = 1.0f;
02969 //  alpha = materialcache[matindex].opacity;
02970 
02971   // XXX we are currently converting to triangle soup for ease of
02972   // initial implementation, but this is clearly undesirable long-term
02973   int i, ind, ind9, ind12;
02974   for (i=0,ind=0,ind9=0,ind12=0; i<numfacets; i++,ind+=3,ind9+=9,ind12+=12) {
02975     int v0 = facets[ind    ] * 10;
02976     int v1 = facets[ind + 1] * 10;
02977     int v2 = facets[ind + 2] * 10;
02978 
02979     // transform to eye coordinates
02980     wtrans.multpoint3d(cnv + v0 + 7, (float*) &mesh.v[ind9    ]);
02981     wtrans.multpoint3d(cnv + v1 + 7, (float*) &mesh.v[ind9 + 3]);
02982     wtrans.multpoint3d(cnv + v2 + 7, (float*) &mesh.v[ind9 + 6]);
02983 
02984     wtrans.multnorm3d(cnv + v0 + 4, (float*) &mesh.n[ind9    ]);
02985     wtrans.multnorm3d(cnv + v1 + 4, (float*) &mesh.n[ind9 + 3]);
02986     wtrans.multnorm3d(cnv + v2 + 4, (float*) &mesh.n[ind9 + 6]);
02987 
02988     vec_copy(&mesh.c[ind12    ], cnv + v0);
02989     mesh.c[ind12 +  3] = alpha;
02990     vec_copy(&mesh.c[ind12 + 4], cnv + v1);
02991     mesh.c[ind12 +  7] = alpha;
02992     vec_copy(&mesh.c[ind12 + 8], cnv + v2);
02993     mesh.c[ind12 + 11] = alpha;
02994 
02995     mesh.f[i*3  ] = i*3;
02996     mesh.f[i*3+1] = i*3 + 1;
02997     mesh.f[i*3+2] = i*3 + 2;
02998   }
02999 
03000   attach_mesh(numfacets * 3, numfacets, matindex, mesh);
03001 }
03002 
03003 
03004 
03005 // 
03006 // This implementation translates from the most-compact host representation
03007 // to the best that ANARI allows
03008 //
03009 void ANARIRender::trimesh_c4u_n3b_v3f(Matrix4 & wtrans, unsigned char *c, 
03010                                       signed char *n, float *v, 
03011                                       int numfacets, int matindex) {
03012   if (!context_created) return;
03013   if (verbose == RT_VERB_DEBUG) printf("ANARIRenderer) creating trimesh_c4u_n3b_v3f: %d...\n", numfacets);
03014   trimesh_n3b_v3f_cnt += numfacets;
03015 
03016   // create and fill the ANARI trimesh memory buffer
03017   anr_trimesh_v3f_n3f_c3f mesh;
03018   memset(&mesh, 0, sizeof(mesh));
03019   mesh.num = numfacets;
03020   mesh.v = (float *) calloc(1, numfacets * 9*sizeof(float));
03021   mesh.n = (float *) calloc(1, numfacets * 9*sizeof(float));
03022   mesh.c = (float *) calloc(1, numfacets * 12*sizeof(float));
03023   mesh.f = (int *) calloc(1, numfacets * 3*sizeof(int));
03024  
03025   float alpha = 1.0f;
03026 //  alpha = materialcache[matindex].opacity;
03027 
03028   // XXX we are currently converting to triangle soup for ease of
03029   // initial implementation, but this is clearly undesirable long-term
03030   int i, ind, ind9, ind12;
03031 
03032   const float ci2f = 1.0f / 255.0f;
03033   const float cn2f = 1.0f / 127.5f;
03034   for (i=0,ind=0,ind9=0,ind12=0; i<numfacets; i++,ind+=3,ind9+=9,ind12+=12) {
03035     float norm[9];
03036 
03037     // conversion from GLbyte format, Table 2.6, p. 44 of OpenGL spec 1.2.1
03038     // float = (2c+1)/(2^8-1)
03039     norm[0] = n[ind9    ] * cn2f + ci2f;
03040     norm[1] = n[ind9 + 1] * cn2f + ci2f;
03041     norm[2] = n[ind9 + 2] * cn2f + ci2f;
03042     norm[3] = n[ind9 + 3] * cn2f + ci2f;
03043     norm[4] = n[ind9 + 4] * cn2f + ci2f;
03044     norm[5] = n[ind9 + 5] * cn2f + ci2f;
03045     norm[6] = n[ind9 + 6] * cn2f + ci2f;
03046     norm[7] = n[ind9 + 7] * cn2f + ci2f;
03047     norm[8] = n[ind9 + 8] * cn2f + ci2f;
03048 
03049     // transform to eye coordinates
03050     wtrans.multpoint3d(v + ind9    , (float*) &mesh.v[ind9    ]);
03051     wtrans.multpoint3d(v + ind9 + 3, (float*) &mesh.v[ind9 + 3]);
03052     wtrans.multpoint3d(v + ind9 + 6, (float*) &mesh.v[ind9 + 6]);
03053 
03054     wtrans.multnorm3d(norm    , (float*) &mesh.n[ind9    ]);
03055     wtrans.multnorm3d(norm + 3, (float*) &mesh.n[ind9 + 3]);
03056     wtrans.multnorm3d(norm + 6, (float*) &mesh.n[ind9 + 6]);
03057 
03058     float col[9];
03059 
03060     // conversion from GLubyte format, Table 2.6, p. 44 of OpenGL spec 1.2.1
03061     // float = c/(2^8-1)
03062     col[0] = c[ind12     ] * ci2f;
03063     col[1] = c[ind12 +  1] * ci2f;
03064     col[2] = c[ind12 +  2] * ci2f;
03065     col[3] = c[ind12 +  4] * ci2f;
03066     col[4] = c[ind12 +  5] * ci2f;
03067     col[5] = c[ind12 +  6] * ci2f;
03068     col[6] = c[ind12 +  8] * ci2f;
03069     col[7] = c[ind12 +  9] * ci2f;
03070     col[8] = c[ind12 + 10] * ci2f;
03071 
03072     vec_copy(&mesh.c[ind12    ], col    );
03073     mesh.c[ind12 +  3] = alpha;
03074     vec_copy(&mesh.c[ind12 + 4], col + 3);
03075     mesh.c[ind12 +  7] = alpha;
03076     vec_copy(&mesh.c[ind12 + 8], col + 6);
03077     mesh.c[ind12 + 11] = alpha;
03078 
03079     mesh.f[i*3  ] = i*3;
03080     mesh.f[i*3+1] = i*3 + 1;
03081     mesh.f[i*3+2] = i*3 + 2;
03082   }
03083 
03084   attach_mesh(numfacets * 3, numfacets, matindex, mesh);
03085 }
03086 
03087 
03088 
03089 void ANARIRender::trimesh_c4u_n3f_v3f(Matrix4 & wtrans, unsigned char *c, 
03090                                       float *n, float *v, 
03091                                       int numfacets, int matindex) {
03092   if (!context_created) return;
03093   if (verbose == RT_VERB_DEBUG) printf("ANARIRenderer) creating trimesh_c4u_n3f_v3f: %d...\n", numfacets);
03094   tricolor_cnt += numfacets;
03095 
03096   // create and fill the ANARI trimesh memory buffer
03097   anr_trimesh_v3f_n3f_c3f mesh;
03098   memset(&mesh, 0, sizeof(mesh));
03099   mesh.num = numfacets;
03100   mesh.v = (float *) calloc(1, numfacets * 9*sizeof(float));
03101   mesh.n = (float *) calloc(1, numfacets * 9*sizeof(float));
03102   mesh.c = (float *) calloc(1, numfacets * 12*sizeof(float));
03103   mesh.f = (int *) calloc(1, numfacets * 3*sizeof(int));
03104  
03105   float alpha = 1.0f;
03106 //  alpha = materialcache[matindex].opacity;
03107 
03108   // XXX we are currently converting to triangle soup for ease of
03109   // initial implementation, but this is clearly undesirable long-term
03110   int i, ind, ind9, ind12;
03111 
03112   const float ci2f = 1.0f / 255.0f;
03113   for (i=0,ind=0,ind9=0,ind12=0; i<numfacets; i++,ind+=3,ind9+=9,ind12+=12) {
03114     // transform to eye coordinates
03115     wtrans.multpoint3d(v + ind9    , (float*) &mesh.v[ind9    ]);
03116     wtrans.multpoint3d(v + ind9 + 3, (float*) &mesh.v[ind9 + 3]);
03117     wtrans.multpoint3d(v + ind9 + 6, (float*) &mesh.v[ind9 + 6]);
03118 
03119     wtrans.multnorm3d(n + ind9    , &mesh.n[ind9    ]);
03120     wtrans.multnorm3d(n + ind9 + 3, &mesh.n[ind9 + 3]);
03121     wtrans.multnorm3d(n + ind9 + 6, &mesh.n[ind9 + 3]);
03122 
03123     // conversion from GLubyte format, Table 2.6, p. 44 of OpenGL spec 1.2.1
03124     // float = c/(2^8-1)
03125     float col[9];
03126     col[0] = c[ind12     ] * ci2f;
03127     col[1] = c[ind12 +  1] * ci2f;
03128     col[2] = c[ind12 +  2] * ci2f;
03129     col[3] = c[ind12 +  4] * ci2f;
03130     col[4] = c[ind12 +  5] * ci2f;
03131     col[5] = c[ind12 +  6] * ci2f;
03132     col[6] = c[ind12 +  8] * ci2f;
03133     col[7] = c[ind12 +  9] * ci2f;
03134     col[8] = c[ind12 + 10] * ci2f;
03135 
03136     vec_copy(&mesh.c[ind12    ], col    );
03137     mesh.c[ind12 +  3] = alpha;
03138     vec_copy(&mesh.c[ind12 + 4], col + 3);
03139     mesh.c[ind12 +  7] = alpha;
03140     vec_copy(&mesh.c[ind12 + 8], col + 6);
03141     mesh.c[ind12 + 11] = alpha;
03142 
03143     mesh.f[i*3  ] = i*3;
03144     mesh.f[i*3+1] = i*3 + 1;
03145     mesh.f[i*3+2] = i*3 + 2;
03146   }
03147 
03148   attach_mesh(numfacets * 3, numfacets, matindex, mesh);
03149 }
03150 
03151 
03152 void ANARIRender::trimesh_n3b_v3f(Matrix4 & wtrans, float *uniform_color, 
03153                                   signed char *n, float *v, 
03154                                   int numfacets, int matindex) {
03155   if (!context_created) return;
03156   if (verbose == RT_VERB_DEBUG) printf("ANARIRenderer) creating trimesh_n3b_v3f: %d...\n", numfacets);
03157   trimesh_n3b_v3f_cnt += numfacets;
03158 
03159   // create and fill the ANARI trimesh memory buffer
03160   anr_trimesh_v3f_n3f_c3f mesh;
03161   memset(&mesh, 0, sizeof(mesh));
03162   mesh.num = numfacets;
03163   mesh.v = (float *) calloc(1, numfacets * 9*sizeof(float));
03164   mesh.n = (float *) calloc(1, numfacets * 9*sizeof(float));
03165   mesh.c = (float *) calloc(1, numfacets * 12*sizeof(float));
03166   mesh.f = (int *) calloc(1, numfacets * 3*sizeof(int));
03167  
03168   float alpha = 1.0f;
03169 
03170   // XXX we are currently converting to triangle soup for ease of
03171   // initial implementation, but this is clearly undesirable long-term
03172   int i, ind, ind9, ind12;
03173 
03174   const float ci2f = 1.0f / 255.0f;
03175   const float cn2f = 1.0f / 127.5f;
03176   for (i=0,ind=0,ind9=0,ind12=0; i<numfacets; i++,ind+=3,ind9+=9,ind12+=12) {
03177     float norm[9];
03178 
03179     // conversion from GLbyte format, Table 2.6, p. 44 of OpenGL spec 1.2.1
03180     // float = (2c+1)/(2^8-1)
03181     norm[0] = n[ind9    ] * cn2f + ci2f;
03182     norm[1] = n[ind9 + 1] * cn2f + ci2f;
03183     norm[2] = n[ind9 + 2] * cn2f + ci2f;
03184     norm[3] = n[ind9 + 3] * cn2f + ci2f;
03185     norm[4] = n[ind9 + 4] * cn2f + ci2f;
03186     norm[5] = n[ind9 + 5] * cn2f + ci2f;
03187     norm[6] = n[ind9 + 6] * cn2f + ci2f;
03188     norm[7] = n[ind9 + 7] * cn2f + ci2f;
03189     norm[8] = n[ind9 + 8] * cn2f + ci2f;
03190 
03191     // transform to eye coordinates
03192     wtrans.multpoint3d(v + ind9    , (float*) &mesh.v[ind9    ]);
03193     wtrans.multpoint3d(v + ind9 + 3, (float*) &mesh.v[ind9 + 3]);
03194     wtrans.multpoint3d(v + ind9 + 6, (float*) &mesh.v[ind9 + 6]);
03195 
03196     wtrans.multnorm3d(norm    , (float*) &mesh.n[ind9    ]);
03197     wtrans.multnorm3d(norm + 3, (float*) &mesh.n[ind9 + 3]);
03198     wtrans.multnorm3d(norm + 6, (float*) &mesh.n[ind9 + 6]);
03199 
03200     vec_copy(&mesh.c[ind12    ], uniform_color);
03201     mesh.c[ind12 +  3] = alpha;
03202     vec_copy(&mesh.c[ind12 + 4], uniform_color);
03203     mesh.c[ind12 +  7] = alpha;
03204     vec_copy(&mesh.c[ind12 + 8], uniform_color);
03205     mesh.c[ind12 + 11] = alpha;
03206 
03207     mesh.f[i*3  ] = i*3;
03208     mesh.f[i*3+1] = i*3 + 1;
03209     mesh.f[i*3+2] = i*3 + 2;
03210   }
03211 
03212   attach_mesh(numfacets * 3, numfacets, matindex, mesh);
03213 }
03214 
03215 
03216 // XXX At present we have to build/populate a per-vertex color arrays,
03217 //     but that should go away as soon as ANARI allows it.
03218 void ANARIRender::trimesh_n3f_v3f(Matrix4 & wtrans, float *uniform_color, 
03219                                   float *n, float *v, int numfacets, 
03220                                   int matindex) {
03221   DBG();
03222   if (!context_created) return;
03223   if (verbose == RT_VERB_DEBUG) printf("ANARIRenderer) creating trimesh_n3f_v3f: %d...\n", numfacets);
03224   trimesh_n3f_v3f_cnt += numfacets;
03225   // create and fill the ANARI trimesh memory buffer
03226   anr_trimesh_v3f_n3f_c3f mesh;
03227   memset(&mesh, 0, sizeof(mesh));
03228   mesh.num = numfacets;
03229   mesh.v = (float *) calloc(1, numfacets * 9*sizeof(float));
03230   mesh.n = (float *) calloc(1, numfacets * 9*sizeof(float));
03231   mesh.c = (float *) calloc(1, numfacets * 12*sizeof(float));
03232   mesh.f = (int *) calloc(1, numfacets * 3*sizeof(int));
03233 
03234   float alpha = 1.0f;
03235 
03236   // create and fill the ANARI trimesh memory buffer
03237   int i, ind, ind9, ind12;
03238 
03239   for (i=0,ind=0,ind9=0,ind12=0; i<numfacets; i++,ind+=3,ind9+=9,ind12+=12) {
03240     // transform to eye coordinates
03241     wtrans.multpoint3d(v + ind9    , (float*) &mesh.v[ind9    ]);
03242     wtrans.multpoint3d(v + ind9 + 3, (float*) &mesh.v[ind9 + 3]);
03243     wtrans.multpoint3d(v + ind9 + 6, (float*) &mesh.v[ind9 + 6]);
03244 
03245     wtrans.multnorm3d(n + ind9    , (float*) &mesh.n[ind9    ]);
03246     wtrans.multnorm3d(n + ind9 + 3, (float*) &mesh.n[ind9 + 3]);
03247     wtrans.multnorm3d(n + ind9 + 6, (float*) &mesh.n[ind9 + 6]);
03248 
03249     vec_copy(&mesh.c[ind12    ], uniform_color);
03250     mesh.c[ind12 +  3] = alpha;
03251     vec_copy(&mesh.c[ind12 + 4], uniform_color);
03252     mesh.c[ind12 +  7] = alpha;
03253     vec_copy(&mesh.c[ind12 + 8], uniform_color);
03254     mesh.c[ind12 + 11] = alpha;
03255 
03256     mesh.f[i*3  ] = i*3;
03257     mesh.f[i*3+1] = i*3 + 1;
03258     mesh.f[i*3+2] = i*3 + 2;
03259   }
03260 
03261   attach_mesh(numfacets * 3, numfacets, matindex, mesh);
03262 }
03263 
03264 
03265 #if 0
03266 void ANARIRender::trimesh_v3f(Matrix4 & wtrans, float *uniform_color, 
03267                               float *v, int numfacets, int matindex) {
03268   if (!context_created) return;
03269   if (verbose == RT_VERB_DEBUG) printf("ANARIRenderer) creating trimesh_v3f: %d...\n", numfacets);
03270   trimesh_v3f_cnt += numfacets;
03271 
03272   set_material(geom, matindex, NULL);
03273   append_objects(buf, geom, instance);
03274 }
03275 
03276 #endif
03277 
03278 
03279 
03280 void ANARIRender::tristrip(Matrix4 & wtrans, int numverts, const float * cnv,
03281                            int numstrips, const int *vertsperstrip,
03282                            const int *facets, int matindex) {
03283   if (!context_created) return;
03284   int i;
03285   int numfacets = 0;
03286   for (i=0; i<numstrips; i++) 
03287     numfacets += (vertsperstrip[i] - 2);  
03288 
03289   if (verbose == RT_VERB_DEBUG) printf("ANARIRenderer) creating tristrip: %d...\n", numfacets);
03290   tricolor_cnt += numfacets;
03291 
03292   // create and fill the ANARI trimesh memory buffer
03293   anr_trimesh_v3f_n3f_c3f mesh;
03294   memset(&mesh, 0, sizeof(mesh));
03295   mesh.num = numfacets;
03296   mesh.v = (float *) calloc(1, numfacets * 9*sizeof(float));
03297   mesh.n = (float *) calloc(1, numfacets * 9*sizeof(float));
03298   mesh.c = (float *) calloc(1, numfacets * 12*sizeof(float));
03299   mesh.f = (int *) calloc(1, numfacets * 3*sizeof(int));
03300 
03301   float alpha = 1.0f;
03302 //  alpha = materialcache[matindex].opacity;
03303 
03304   // XXX we are currently converting to triangle soup for ease of
03305   // initial implementation, but this is clearly undesirable long-term
03306 
03307   // render triangle strips one triangle at a time
03308   // triangle winding order is:
03309   //   v0, v1, v2, then v2, v1, v3, then v2, v3, v4, etc.
03310   int strip, t, v = 0;
03311   int stripaddr[2][3] = { {0, 1, 2}, {1, 0, 2} };
03312 
03313   // loop over all of the triangle strips
03314   i=0; // set triangle index to 0
03315   int ind9, ind12;
03316   for (strip=0,ind9=0,ind12=0; strip < numstrips; strip++) {
03317     // loop over all triangles in this triangle strip
03318     for (t = 0; t < (vertsperstrip[strip] - 2); t++) {
03319       // render one triangle, using lookup table to fix winding order
03320       int v0 = facets[v + (stripaddr[t & 0x01][0])] * 10;
03321       int v1 = facets[v + (stripaddr[t & 0x01][1])] * 10;
03322       int v2 = facets[v + (stripaddr[t & 0x01][2])] * 10;
03323 
03324       // transform to eye coordinates
03325       wtrans.multpoint3d(cnv + v0 + 7, (float*) &mesh.v[ind9    ]);
03326       wtrans.multpoint3d(cnv + v1 + 7, (float*) &mesh.v[ind9 + 3]);
03327       wtrans.multpoint3d(cnv + v2 + 7, (float*) &mesh.v[ind9 + 6]);
03328 
03329       wtrans.multnorm3d(cnv + v0 + 4, (float*) &mesh.n[ind9    ]);
03330       wtrans.multnorm3d(cnv + v1 + 4, (float*) &mesh.n[ind9 + 3]);
03331       wtrans.multnorm3d(cnv + v2 + 4, (float*) &mesh.n[ind9 + 6]);
03332 
03333       vec_copy(&mesh.c[ind12    ], cnv + v0);
03334       mesh.c[ind12 +  3] = alpha;
03335       vec_copy(&mesh.c[ind12 + 4], cnv + v1);
03336       mesh.c[ind12 +  7] = alpha;
03337       vec_copy(&mesh.c[ind12 + 8], cnv + v2);
03338       mesh.c[ind12 + 11] = alpha;
03339 
03340       mesh.f[i*3  ] = i*3;
03341       mesh.f[i*3+1] = i*3 + 1;
03342       mesh.f[i*3+2] = i*3 + 2;
03343 
03344       v++; // move on to next vertex
03345       i++; // next triangle
03346       ind9+=9;
03347       ind12+=12;
03348     }
03349     v+=2; // last two vertices are already used by last triangle
03350   }
03351 
03352   attach_mesh(numfacets * 3, numfacets, matindex, mesh);
03353 }
03354 
03355 
03356 

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