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

OptiXRenderer.C

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

Generated on Mon Nov 17 02:46:49 2025 for VMD (current) by doxygen1.2.14 written by Dimitri van Heesch, © 1997-2002

AltStyle によって変換されたページ (->オリジナル) /