00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00075
00076
00077
00078 #include "OptiXDisplayDevice.h"
00079 #include "OptiXRenderer.h"
00080
00081 #include <math.h>
00082 #include <stdlib.h>
00083 #include <stdio.h>
00084 #include <string.h>
00085
00086 #include "VMDApp.h"
00087 #include "QuickSurf.h"
00088 #include "VideoStream.h"
00089
00090 #include "DispCmds.h"
00091 #include "config.h"
00092 #include "Hershey.h"
00093
00094 #include "ProfileHooks.h"
00095
00096
00097
00098 #define DEFAULT_RADIUS 0.0025f
00099
00101 OptiXDisplayDevice::OptiXDisplayDevice(VMDApp *app, int interactive) : FileRenderer((interactive) ?
00102 "TachyonLOptiXInteractive" : "TachyonLOptiXInternal",
00103 (interactive) ?
00104 "TachyonL-OptiX (interactive, GPU-accelerated)" : "TachyonL-OptiX (internal, in-memory, GPU-accelerated)",
00105 "vmdscene.ppm", DEF_VMDIMAGEVIEWER) {
00106
00107 PROFILE_PUSH_RANGE((interactive) ? "OptiXDisplayDevice::OptiXDisplayDevice(INTERACTIVE)" : "OptiXDisplayDevice::OptiXDisplayDevice(BATCH)", 0);
00108
00109 vmdapp = app;
00110
00111 reset_vars();
00112
00113
00114 isinteractive = interactive;
00115
00116
00117 formats.add_name("PPM", 0);
00118
00119
00120 curformat = 0;
00121
00122
00123 has_aa = TRUE;
00124 aasamples = 12;
00125 aosamples = 12;
00126
00127 ort = new OptiXRenderer(vmdapp);
00128 ort_timer = wkf_timer_create();
00129
00130 PROFILE_POP_RANGE();
00131 }
00132
00134 OptiXDisplayDevice::~OptiXDisplayDevice(void) {
00135 PROFILE_PUSH_RANGE("OptiXDisplayDevice::~OptiXDisplayDevice()", 0);
00136
00137 delete ort;
00138 wkf_timer_destroy(ort_timer);
00139
00140 PROFILE_POP_RANGE();
00141 }
00142
00143
00145 unsigned int OptiXDisplayDevice::device_count(void) {
00146 return OptiXRenderer::device_count();
00147 }
00148
00149
00150 void OptiXDisplayDevice::add_material(void) {
00151 ort->add_material(materialIndex,
00152 mat_ambient, mat_diffuse, mat_specular, mat_shininess,
00153 mat_mirror, mat_opacity, mat_outline, mat_outlinewidth,
00154 roundf(mat_transmode));
00155
00156 }
00157
00158
00160 void OptiXDisplayDevice::reset_vars(void) {
00161 reset_cylinder_buffer();
00162 reset_sphere_buffer();
00163 reset_triangle_buffer();
00164 }
00165
00166
00167 void OptiXDisplayDevice::send_cylinder_buffer() {
00168 if (cylinder_vert_buffer.num() > 0) {
00169
00170 ort->cylinder_array_color(cylinder_xform, cylinder_radius_scalefactor,
00171 cylinder_vert_buffer.num()/6,
00172 &cylinder_vert_buffer[0],
00173 &cylinder_radii_buffer[0],
00174 &cylinder_color_buffer[0],
00175 cylinder_matindex);
00176
00177
00178 if (cylcap_vert_buffer.num() > 0) {
00179 ort->ring_array_color(*cylinder_xform, cylinder_radius_scalefactor,
00180 cylcap_vert_buffer.num()/3,
00181 &cylcap_vert_buffer[0],
00182 &cylcap_norm_buffer[0],
00183 &cylcap_radii_buffer[0],
00184 &cylcap_color_buffer[0],
00185 cylinder_matindex);
00186 }
00187
00188 delete cylinder_xform;
00189 }
00190 reset_cylinder_buffer();
00191 }
00192
00193
00194
00195 void OptiXDisplayDevice::cylinder(float *a, float *b, float r, int filled) {
00196
00197
00198 if (
00199 #if 1
00200
00201
00202
00203
00204 cylinder_vert_buffer.num() >= 15000000 ||
00205 #endif
00206 (cylinder_xform != NULL && ((cylinder_matindex != materialIndex) || (memcmp(cylinder_xform->mat, transMat.top().mat, sizeof(cylinder_xform->mat)))))) {
00207 send_cylinder_buffer();
00208 }
00209
00210
00211 if (cylinder_xform == NULL) {
00212
00213 cylinder_matindex = materialIndex;
00214 cylinder_xform = new Matrix4(transMat.top());
00215 cylinder_radius_scalefactor = scale_factor();
00216 add_material();
00217 }
00218
00219
00220 cylinder_vert_buffer.append2x3(&a[0], &b[0]);
00221 cylinder_radii_buffer.append(r);
00222 cylinder_color_buffer.append3(&matData[colorIndex][0]);
00223
00224
00225 if (filled) {
00226 float norm[3];
00227 norm[0] = b[0] - a[0];
00228 norm[1] = b[1] - a[1];
00229 norm[2] = b[2] - a[2];
00230
00231 float div = 1.0f / sqrtf(norm[0]*norm[0] + norm[1]*norm[1] + norm[2]*norm[2]);
00232 norm[0] *= div;
00233 norm[1] *= div;
00234 norm[2] *= div;
00235
00236 if (filled & CYLINDER_TRAILINGCAP) {
00237 cylcap_vert_buffer.append3(&a[0]);
00238 cylcap_norm_buffer.append3(&norm[0]);
00239 cylcap_radii_buffer.append2(0.0f, r);
00240 cylcap_color_buffer.append3(&matData[colorIndex][0]);
00241 }
00242
00243 if (filled & CYLINDER_LEADINGCAP) {
00244 cylcap_vert_buffer.append3(&b[0]);
00245 norm[0] *= -1;
00246 norm[1] *= -1;
00247 norm[2] *= -1;
00248 cylcap_norm_buffer.append3(&norm[0]);
00249 cylcap_radii_buffer.append2(0.0f, r);
00250 cylcap_color_buffer.append3(&matData[colorIndex][0]);
00251 }
00252 }
00253 }
00254
00255
00256 void OptiXDisplayDevice::send_sphere_buffer() {
00257 if (sphere_vert_buffer.num() > 0) {
00258
00259 ort->sphere_array_color(*sphere_xform, sphere_radius_scalefactor,
00260 sphere_vert_buffer.num()/3,
00261 &sphere_vert_buffer[0],
00262 &sphere_radii_buffer[0],
00263 &sphere_color_buffer[0],
00264 sphere_matindex);
00265
00266 delete sphere_xform;
00267 }
00268 reset_sphere_buffer();
00269 }
00270
00271
00272
00273 void OptiXDisplayDevice::sphere(float *xyzr) {
00274 #if 0
00275 add_material();
00276
00277
00278 ort->sphere_array_color(transMat.top(), scale_factor(), 1,
00279 xyzr, xyzr+3, &matData[colorIndex][0], materialIndex);
00280 #else
00281
00282
00283 if (
00284 #if 1
00285
00286
00287
00288
00289 sphere_vert_buffer.num() >= 15000000 ||
00290 #endif
00291 (sphere_xform != NULL && ((sphere_matindex != materialIndex) || (memcmp(sphere_xform->mat, transMat.top().mat, sizeof(sphere_xform->mat)))))) {
00292 send_sphere_buffer();
00293 }
00294
00295
00296 if (sphere_xform == NULL) {
00297
00298 sphere_matindex = materialIndex;
00299 sphere_xform = new Matrix4(transMat.top());
00300 sphere_radius_scalefactor = scale_factor();
00301 add_material();
00302 }
00303
00304
00305 sphere_vert_buffer.append3(xyzr);
00306 sphere_radii_buffer.append(xyzr[3]);
00307 sphere_color_buffer.append3(&matData[colorIndex][0]);
00308 #endif
00309 }
00310
00311
00312
00313 void OptiXDisplayDevice::sphere_array(int spnum, int spres, float *centers,
00314 float *radii, float *colors) {
00315 add_material();
00316
00317 #if 1
00318
00319
00320
00321
00322 int spleft=spnum;
00323 while (spleft > 0) {
00324 int spcount=spleft;
00325 if (spcount > 6000000) {
00326 spcount=5000000;
00327 }
00328
00329 long offset = spnum - spleft;
00330 long offset3 = 3L * offset;
00331 ort->sphere_array_color(transMat.top(), scale_factor(), spcount,
00332 centers+offset3, radii+offset, colors+offset3, materialIndex);
00333 spleft-=spcount;
00334 }
00335 #else
00336
00337 ort->sphere_array_color(transMat.top(), scale_factor(), spnum,
00338 centers, radii, colors, materialIndex);
00339 #endif
00340
00341
00342 int ind=(spnum-1)*3;
00343 super_set_color(nearest_index(colors[ind], colors[ind+1], colors[ind+2]));
00344 }
00345
00346
00347 void OptiXDisplayDevice::text(float *pos, float size, float thickness,
00348 const char *str) {
00349 float textpos[3];
00350 float textsize, textthickness;
00351 hersheyhandle hh;
00352
00353
00354 (transMat.top()).multpoint3d(pos, textpos);
00355 textsize = size * 1.5f;
00356 textthickness = thickness*DEFAULT_RADIUS;
00357
00358 ResizeArray<float> text_spheres;
00359 ResizeArray<float> text_cylinders;
00360
00361 while (*str != '\0') {
00362 float lm, rm, x, y, ox, oy;
00363 int draw, odraw;
00364 ox=oy=x=y=0.0f;
00365 draw=odraw=0;
00366
00367 hersheyDrawInitLetter(&hh, *str, &lm, &rm);
00368 textpos[0] -= lm * textsize;
00369
00370 while (!hersheyDrawNextLine(&hh, &draw, &x, &y)) {
00371 float oldpt[3], newpt[3];
00372 if (draw) {
00373 newpt[0] = textpos[0] + textsize * x;
00374 newpt[1] = textpos[1] + textsize * y;
00375 newpt[2] = textpos[2];
00376
00377 if (odraw) {
00378
00379 oldpt[0] = textpos[0] + textsize * ox;
00380 oldpt[1] = textpos[1] + textsize * oy;
00381 oldpt[2] = textpos[2];
00382
00383 text_cylinders.append2x3(&oldpt[0], &newpt[0]);
00384 text_spheres.append3(&newpt[0]);
00385 } else {
00386
00387 text_spheres.append3(&newpt[0]);
00388 }
00389 }
00390
00391 ox=x;
00392 oy=y;
00393 odraw=draw;
00394 }
00395 textpos[0] += rm * textsize;
00396
00397 str++;
00398 }
00399
00400 add_material();
00401
00402 if (text_cylinders.num() > 0) {
00403 ort->cylinder_array(NULL, textthickness, matData[colorIndex],
00404 text_cylinders.num() / 6, &text_cylinders[0],
00405 materialIndex);
00406 }
00407 if (text_spheres.num() > 0) {
00408 ort->sphere_array(NULL, textthickness, matData[colorIndex],
00409 text_spheres.num() / 3, &text_spheres[0], NULL,
00410 materialIndex);
00411 }
00412 }
00413
00414
00415
00416 void OptiXDisplayDevice::send_triangle_buffer() {
00417 if (triangle_vert_buffer.num() > 0) {
00418 ort->trimesh_n3f_v3f(*triangle_xform,
00419 matData[triangle_cindex],
00420 &triangle_norm_buffer[0],
00421 &triangle_vert_buffer[0],
00422 triangle_vert_buffer.num()/9,
00423 triangle_matindex);
00424 delete triangle_xform;
00425 }
00426 reset_triangle_buffer();
00427 }
00428
00429
00430
00431 void OptiXDisplayDevice::triangle(const float *a, const float *b, const float *c, const float *n1, const float *n2, const float *n3) {
00432
00433
00434 if (triangle_xform != NULL && ((triangle_cindex != colorIndex) || (triangle_matindex != materialIndex) || (memcmp(triangle_xform->mat, transMat.top().mat, sizeof(triangle_xform->mat))))) {
00435 send_triangle_buffer();
00436 }
00437
00438
00439 if (triangle_xform == NULL) {
00440
00441 triangle_cindex = colorIndex;
00442 triangle_matindex = materialIndex;
00443 triangle_xform = new Matrix4(transMat.top());
00444 add_material();
00445 }
00446
00447
00448 triangle_vert_buffer.append3x3(&a[0], &b[0], &c[0]);
00449
00450
00451 triangle_norm_buffer.append3x3(&n1[0], &n2[0], &n3[0]);
00452 }
00453
00454
00455
00456 void OptiXDisplayDevice::tricolor(const float *a, const float *b, const float *c,
00457 const float *n1, const float *n2, const float *n3,
00458 const float *c1, const float *c2, const float *c3) {
00459 add_material();
00460
00461 float vnc[27];
00462 vec_copy(&vnc[ 0], a);
00463 vec_copy(&vnc[ 3], b);
00464 vec_copy(&vnc[ 6], c);
00465
00466 vec_copy(&vnc[ 9], n1);
00467 vec_copy(&vnc[12], n2);
00468 vec_copy(&vnc[15], n3);
00469
00470 vec_copy(&vnc[18], c1);
00471 vec_copy(&vnc[21], c2);
00472 vec_copy(&vnc[24], c3);
00473
00474 ort->tricolor_list(transMat.top(), 1, vnc, materialIndex);
00475 }
00476
00477
00478 void OptiXDisplayDevice::trimesh_c4u_n3b_v3f(unsigned char *c,
00479 signed char *n,
00480 float *v, int numfacets) {
00481 add_material();
00482 ort->trimesh_c4u_n3b_v3f(transMat.top(), c, n, v, numfacets, materialIndex);
00483 }
00484
00485
00486 void OptiXDisplayDevice::trimesh_c4u_n3f_v3f(unsigned char *c, float *n,
00487 float *v, int numfacets) {
00488 add_material();
00489 ort->trimesh_c4u_n3f_v3f(transMat.top(), c, n, v, numfacets, materialIndex);
00490 }
00491
00492
00493 void OptiXDisplayDevice::trimesh_c4n3v3(int numverts, float * cnv,
00494 int numfacets, int * facets) {
00495 add_material();
00496 ort->trimesh_c4n3v3(transMat.top(), numverts, cnv, numfacets, facets,
00497 materialIndex);
00498 }
00499
00500
00501 void OptiXDisplayDevice::trimesh_n3b_v3f(signed char *n, float *v,
00502 int numfacets) {
00503 add_material();
00504 ort->trimesh_n3b_v3f(transMat.top(), matData[colorIndex], n, v, numfacets, materialIndex);
00505 }
00506
00507
00508 void OptiXDisplayDevice::trimesh_n3f_v3f(float *n, float *v, int numfacets) {
00509 add_material();
00510 ort->trimesh_n3f_v3f(transMat.top(), matData[colorIndex], n, v, numfacets, materialIndex);
00511 }
00512
00513
00514 void OptiXDisplayDevice::trimesh_n3fopt_v3f(float *n, float *v, int numfacets) {
00515 add_material();
00516 ort->trimesh_v3f(transMat.top(), matData[colorIndex], v, numfacets, materialIndex);
00517 }
00518
00519
00520 void OptiXDisplayDevice::tristrip(int numverts, const float * cnv,
00521 int numstrips, const int *vertsperstrip,
00522 const int *facets) {
00523 add_material();
00524 ort->tristrip(transMat.top(), numverts, cnv, numstrips, vertsperstrip,
00525 facets, materialIndex);
00526 }
00527
00528
00529 void OptiXDisplayDevice::write_lights() {
00530 int i;
00531 int lightcount = 0;
00532
00533
00534
00535 ort->clear_all_lights();
00536
00537
00538 for (i=0; i<DISP_LIGHTS; i++) {
00539 if (lightState[i].on) {
00540 ort->add_directional_light(lightState[i].pos, lightState[i].color);
00541 lightcount++;
00542 }
00543 }
00544
00545 #if 0
00546
00547 for (i=0; i<DISP_LIGHTS; i++) {
00548 if (advLightState[i].on) {
00549 float pos[3];
00550
00551
00552 vec_copy(pos, advLightState[i].pos);
00553
00554 if (advLightState[i].spoton) {
00555 printf("TachyonInternal) SpotLight not implemented yet ...\n");
00556 } else {
00557 apitexture tex;
00558 memset(&tex, 0, sizeof(apitexture));
00559
00560 tex.col.r=advLightState[i].color[0];
00561 tex.col.g=advLightState[i].color[1];
00562 tex.col.b=advLightState[i].color[2];
00563
00564 void *l = rt_light(rtscene,
00565 rt_texture(rtscene, &tex),
00566
00567 rt_vector(pos[0], pos[1], -pos[2]), 0.0f);
00568
00569
00570 if (advLightState[i].constfactor != 1.0f ||
00571 advLightState[i].linearfactor != 0.0f ||
00572 advLightState[i].quadfactor != 0.0f) {
00573 rt_light_attenuation(l,
00574 advLightState[i].constfactor,
00575 advLightState[i].linearfactor,
00576 advLightState[i].quadfactor);
00577 }
00578 }
00579
00580 lightcount++;
00581 }
00582 }
00583 #endif
00584
00585 if (lightcount < 1) {
00586 msgWarn << "No lights defined in molecular scene!!" << sendmsg;
00587 }
00588
00589 }
00590
00591 void OptiXDisplayDevice::write_materials() {
00592 ort->set_bg_color(backColor);
00593
00594
00595
00596 if (backgroundmode == 1) {
00597 float bspheremag = 0.5f;
00598
00599
00600 switch (projection()) {
00601 case DisplayDevice::ORTHOGRAPHIC:
00602 ort->set_bg_mode(OptiXRenderer::RT_BACKGROUND_TEXTURE_SKY_ORTHO_PLANE);
00603
00604
00605
00606
00607
00608 bspheremag = vSize / 4.0f;
00609 break;
00610
00611 case DisplayDevice::PERSPECTIVE:
00612 default:
00613 ort->set_bg_mode(OptiXRenderer::RT_BACKGROUND_TEXTURE_SKY_SPHERE);
00614
00615
00616
00617
00618
00619 bspheremag = (vSize / 2.0f) / (eyePos[2] - zDist);
00620 if (bspheremag > 1.0f)
00621 bspheremag = 1.0f;
00622 break;
00623 }
00624
00625 ort->set_bg_color_grad_top(backgradienttopcolor);
00626 ort->set_bg_color_grad_bot(backgradientbotcolor);
00627
00628 float updir[3] = { 0.0f, 1.0f, 0.0f };
00629 ort->set_bg_gradient(updir);
00630
00631 ort->set_bg_gradient_topval(bspheremag);
00632 ort->set_bg_gradient_botval(-bspheremag);
00633 } else {
00634 ort->set_bg_mode(OptiXRenderer::RT_BACKGROUND_TEXTURE_SOLID);
00635 }
00636 }
00637
00638
00640
00641 void OptiXDisplayDevice::write_header() {
00642 wkf_timer_start(ort_timer);
00643
00644
00645
00646
00647 if (vmdapp) {
00648
00649
00650
00651
00652
00653
00654
00655
00656 vmdapp->qsurf->free_gpu_memory();
00657 }
00658
00659 ort->setup_context(xSize, ySize);
00660 write_materials();
00661 write_lights();
00662
00663 ort->set_aa_samples(aasamples);
00664
00665
00666 if (shadows_enabled() || ao_enabled()) {
00667 if (shadows_enabled() && !ao_enabled())
00668 msgInfo << "Shadow rendering enabled." << sendmsg;
00669
00670 ort->shadows_on(1);
00671 } else {
00672 ort->shadows_on(0);
00673 }
00674
00675
00676 if (ao_enabled()) {
00677 msgInfo << "Ambient occlusion enabled." << sendmsg;
00678 msgInfo << "Shadow rendering enabled." << sendmsg;
00679 ort->set_ao_samples(aosamples);
00680 } else {
00681 ort->set_ao_samples(0);
00682 }
00683
00684
00685
00686 ort->set_ao_ambient(get_ao_ambient());
00687 ort->set_ao_direct(get_ao_direct());
00688
00689
00690 if (dof_enabled()) {
00691 msgInfo << "DoF focal blur enabled." << sendmsg;
00692 ort->dof_on(1);
00693 ort->set_camera_dof_fnumber(get_dof_fnumber());
00694 ort->set_camera_dof_focal_dist(get_dof_focal_dist());
00695 } else {
00696 ort->dof_on(0);
00697 }
00698
00699
00700 float start = get_cue_start();
00701 float end = get_cue_end();
00702 float density = get_cue_density();
00703 if (cueingEnabled) {
00704 switch (cueMode) {
00705 case CUE_LINEAR:
00706 ort->set_cue_mode(OptiXRenderer::RT_FOG_LINEAR, start, end, density);
00707 break;
00708
00709 case CUE_EXP:
00710 ort->set_cue_mode(OptiXRenderer::RT_FOG_EXP, start, end, density);
00711 break;
00712
00713 case CUE_EXP2:
00714 ort->set_cue_mode(OptiXRenderer::RT_FOG_EXP2, start, end, density);
00715 break;
00716
00717 case NUM_CUE_MODES:
00718
00719 break;
00720 }
00721 } else {
00722 ort->set_cue_mode(OptiXRenderer::RT_FOG_NONE, start, end, density);
00723 }
00724 }
00725
00726
00727 void OptiXDisplayDevice::write_trailer(void){
00728 send_cylinder_buffer();
00729 send_sphere_buffer();
00730 send_triangle_buffer();
00731
00732 switch (projection()) {
00733 case DisplayDevice::ORTHOGRAPHIC:
00734 ort->set_camera_projection(OptiXRenderer::RT_ORTHOGRAPHIC);
00735 ort->set_camera_zoom(0.5f / (1.0f / (vSize / 2.0f)));
00736 break;
00737
00738 case DisplayDevice::PERSPECTIVE:
00739 default:
00740 ort->set_camera_projection(OptiXRenderer::RT_PERSPECTIVE);
00741 ort->set_camera_zoom(0.5f / ((eyePos[2] - zDist) / vSize));
00742 }
00743
00744
00745 ort->set_camera_stereo_eyesep(eyeSep);
00746 ort->set_camera_stereo_convergence_dist(eyeDist);
00747
00748 char *verbstr = getenv("VMDOPTIXVERBOSE");
00749 if (verbstr != NULL) {
00750 if (!strupcmp(verbstr, "TIMING") || !strupcmp(verbstr, "DEBUG")) {
00751 double time_scene_graph = wkf_timer_timenow(ort_timer);
00752 printf("OptiXDisplayDevice) scene graph construction time %.2f\n",
00753 time_scene_graph);
00754 }
00755 }
00756
00757
00758 int writealpha = 0;
00759 if (getenv("VMDOPTIXWRITEALPHA"))
00760 writealpha=1;
00761
00762 #if defined(VMDOPTIX_INTERACTIVE_OPENGL)
00763 if (isinteractive) {
00764 if (vmdapp->display->supports_gui()) {
00765 ort->render_to_glwin(my_filename, writealpha);
00766 } else if (vmdapp->uivs->srv_connected()) {
00767 ort->render_to_videostream(my_filename, writealpha);
00768 }
00769 } else
00770 #else
00771 if (isinteractive && vmdapp->uivs->srv_connected())
00772 ort->render_to_videostream(my_filename, writealpha);
00773 else
00774 #endif
00775 ort->render_to_file(my_filename, writealpha);
00776
00777
00778
00779
00780 if (getenv("VMDOPTIXDESTROYCONTEXT") != NULL) {
00781
00782
00783 delete ort;
00784
00785
00786 ort = new OptiXRenderer(vmdapp);
00787 } else {
00788
00789
00790 ort->destroy_scene();
00791 }
00792
00793 wkf_timer_stop(ort_timer);
00794 printf("OptiXDisplayDevice) Total rendering time: %.2f sec\n", wkf_timer_time(ort_timer));
00795
00796 reset_vars();
00797 }
00798
00799
00800
00801
00802