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 * RCS INFORMATION: 00010 * 00011 * $RCSfile: POV3DisplayDevice.C,v $ 00012 * $Author: johns $ $Locker: $ $State: Exp $ 00013 * $Revision: 1.129 $ $Date: 2020年07月01日 06:09:05 $ 00014 * 00015 ***************************************************************************/ 00021 #include <string.h> 00022 #include <stdio.h> 00023 #include <math.h> 00024 #include "POV3DisplayDevice.h" 00025 #include "Matrix4.h" 00026 #include "Inform.h" 00027 #include "utilities.h" 00028 #include "DispCmds.h" // need for line styles 00029 #include "config.h" // for VMDVERSION string 00030 #include "Hershey.h" // needed for Hershey font rendering fctns 00031 00032 #define DEFAULT_RADIUS 0.002f 00033 #define DASH_LENGTH 0.02f 00034 #define PHONG_DIVISOR 64.0f 00035 00036 // Enable triangle coordinate scaling hacks to prevent POV-Ray 3.x 00037 // from emitting millions of "all determinants too small" warnings 00038 // when rendering finely tessellated geometry. #$@!#@$@ POV-Ray.... 00039 // If/when POV-Ray gets fixed, this hack should gladly be removed. 00040 #define POVRAY_BRAIN_DAMAGE_WORKAROUND 1 00041 #define POVRAY_SCALEHACK 1000.0f 00042 00044 00045 // constructor ... initialize some variables 00046 00047 POV3DisplayDevice::POV3DisplayDevice() : FileRenderer("POV3", "POV-Ray 3.6", "vmdscene.pov", "povray +W%w +H%h -I%s -O%s.tga +D +X +A +FT") { 00048 reset_vars(); // initialize state variables 00049 } 00050 00051 // destructor 00052 POV3DisplayDevice::~POV3DisplayDevice(void) { } 00053 00054 00055 void POV3DisplayDevice::reset_vars(void) { 00056 degenerate_triangles = 0; 00057 degenerate_cylinders = 0; 00058 degenerate_cones = 0; 00059 memset(&clip_on, 0, sizeof(clip_on)); 00060 old_materialIndex = -1; 00061 } 00062 00063 00065 00066 void POV3DisplayDevice::text(float *pos, float size, float thickness, 00067 const char *str) { 00068 float textpos[3]; 00069 float textsize, textthickness; 00070 hersheyhandle hh; 00071 00072 // transform the world coordinates 00073 (transMat.top()).multpoint3d(pos, textpos); 00074 textsize = size * 1.5f; 00075 textthickness = thickness*DEFAULT_RADIUS; 00076 00077 while (*str != '0円') { 00078 float lm, rm, x, y, ox, oy; 00079 int draw, odraw; 00080 ox=oy=x=y=0.0f; 00081 draw=odraw=0; 00082 00083 hersheyDrawInitLetter(&hh, *str, &lm, &rm); 00084 textpos[0] -= lm * textsize; 00085 00086 while (!hersheyDrawNextLine(&hh, &draw, &x, &y)) { 00087 float oldpt[3], newpt[3]; 00088 if (draw) { 00089 newpt[0] = textpos[0] + textsize * x; 00090 newpt[1] = textpos[1] + textsize * y; 00091 newpt[2] = textpos[2]; 00092 00093 if (odraw) { 00094 // if we have both previous and next points, connect them... 00095 oldpt[0] = textpos[0] + textsize * ox; 00096 oldpt[1] = textpos[1] + textsize * oy; 00097 oldpt[2] = textpos[2]; 00098 00099 fprintf(outfile, "VMD_cylinder(<%.8f,%.8f,%.8f>,<%.8f,%.8f,%.8f>", 00100 oldpt[0], oldpt[1], -oldpt[2], newpt[0], newpt[1], -newpt[2]); 00101 fprintf(outfile, "%.4f,rgbt<%.3f,%.3f,%.3f,%.3f>,%d)\n", 00102 textthickness, matData[colorIndex][0], matData[colorIndex][1], 00103 matData[colorIndex][2], 1 - mat_opacity, 1); 00104 00105 fprintf(outfile, "VMD_sphere(<%.4f,%.4f,%.4f>,%.4f,", 00106 newpt[0], newpt[1], -newpt[2], textthickness); 00107 fprintf(outfile, "rgbt<%.3f,%.3f,%.3f,%.3f>)\n", 00108 matData[colorIndex][0], matData[colorIndex][1], 00109 matData[colorIndex][2], 1 - mat_opacity); 00110 } else { 00111 // ...otherwise, just draw the next point 00112 fprintf(outfile, "VMD_sphere(<%.4f,%.4f,%.4f>,%.4f,", 00113 newpt[0], newpt[1], -newpt[2], textthickness); 00114 fprintf(outfile, "rgbt<%.3f,%.3f,%.3f,%.3f>)\n", 00115 matData[colorIndex][0], matData[colorIndex][1], 00116 matData[colorIndex][2], 1 - mat_opacity); 00117 } 00118 } 00119 00120 ox=x; 00121 oy=y; 00122 odraw=draw; 00123 } 00124 textpos[0] += rm * textsize; 00125 00126 str++; 00127 } 00128 } 00129 00130 00131 // draw a point 00132 void POV3DisplayDevice::point(float * spdata) { 00133 float vec[3]; 00134 // transform the world coordinates 00135 (transMat.top()).multpoint3d(spdata, vec); 00136 00137 // write_materials(); 00138 00139 // Draw the point 00140 fprintf(outfile, "VMD_point(<%.4f,%.4f,%.4f>,%.4f,rgbt<%.3f,%.3f,%.3f,%.3f>)\n", 00141 vec[0], vec[1], -vec[2], ((float)pointSize)*DEFAULT_RADIUS, 00142 matData[colorIndex][0], matData[colorIndex][1], 00143 matData[colorIndex][2], 1 - mat_opacity); 00144 } 00145 00146 // draw a sphere 00147 void POV3DisplayDevice::sphere(float * spdata) { 00148 float vec[3]; 00149 float radius; 00150 00151 // transform the world coordinates 00152 (transMat.top()).multpoint3d(spdata, vec); 00153 radius = scale_radius(spdata[3]); 00154 00155 // write_materials(); 00156 00157 // Draw the sphere 00158 fprintf(outfile, "VMD_sphere(<%.4f,%.4f,%.4f>,%.4f,", 00159 vec[0], vec[1], -vec[2], radius); 00160 fprintf(outfile, "rgbt<%.3f,%.3f,%.3f,%.3f>)\n", 00161 matData[colorIndex][0], matData[colorIndex][1], matData[colorIndex][2], 00162 1 - mat_opacity); 00163 } 00164 00165 // draw a line from a to b 00166 void POV3DisplayDevice::line(float *a, float*b) { 00167 int i, j, test; 00168 float dirvec[3], unitdirvec[3]; 00169 float from[3], to[3], tmp1[3], tmp2[3]; 00170 00171 if (lineStyle == ::SOLIDLINE) { 00172 // transform the world coordinates 00173 (transMat.top()).multpoint3d(a, from); 00174 (transMat.top()).multpoint3d(b, to); 00175 00176 // write_materials(); 00177 00178 // Draw the line 00179 fprintf(outfile, "VMD_line(<%.4f,%.4f,%.4f>,<%.4f,%.4f,%.4f>,", 00180 from[0], from[1], -from[2], to[0], to[1], -to[2]); 00181 fprintf(outfile, "rgbt<%.3f,%.3f,%.3f,%.3f>)\n", 00182 matData[colorIndex][0], matData[colorIndex][1], matData[colorIndex][2], 00183 1 - mat_opacity); 00184 00185 } 00186 else if (lineStyle == ::DASHEDLINE) { 00187 // transform the world coordinates 00188 (transMat.top()).multpoint3d(a, tmp1); 00189 (transMat.top()).multpoint3d(b, tmp2); 00190 00191 // how to create a dashed line 00192 vec_sub(dirvec, tmp2, tmp1); // vector from a to b 00193 vec_copy(unitdirvec, dirvec); 00194 vec_normalize(unitdirvec); // unit vector from a to b 00195 test = 1; 00196 i = 0; 00197 while (test == 1) { 00198 for (j=0; j<3; j++) { 00199 from[j] = (float) (tmp1[j] + (2*i)*DASH_LENGTH*unitdirvec[j]); 00200 to[j] = (float) (tmp1[j] + (2*i + 1)*DASH_LENGTH*unitdirvec[j]); 00201 } 00202 if (fabsf(tmp1[0] - to[0]) >= fabsf(dirvec[0])) { 00203 vec_copy(to, tmp2); 00204 test = 0; 00205 } 00206 00207 // write_materials(); 00208 00209 // Draw the line 00210 fprintf(outfile, "VMD_line(<%.4f,%.4f,%.4f>,<%.4f,%.4f,%.4f>,", 00211 from[0], from[1], -from[2], to[0], to[1], -to[2]); 00212 fprintf(outfile, "rgbt<%.3f,%.3f,%.3f,%.3f>)\n", 00213 matData[colorIndex][0], matData[colorIndex][1], matData[colorIndex][2], 00214 1 - mat_opacity); 00215 00216 i++; 00217 } 00218 } 00219 else { 00220 msgErr << "POV3DisplayDevice: Unknown line style " << lineStyle << sendmsg; 00221 } 00222 } 00223 00224 00225 // draw a cylinder 00226 void POV3DisplayDevice::cylinder(float *a, float *b, float r, int filled) { 00227 float from[3], to[3]; 00228 float radius; 00229 00230 // transform the world coordinates 00231 (transMat.top()).multpoint3d(a, from); 00232 (transMat.top()).multpoint3d(b, to); 00233 radius = scale_radius(r); 00234 00235 // check for degenerate cylinders 00236 if ( ((from[0]-to[0])*(from[0]-to[0]) + 00237 (from[1]-to[1])*(from[1]-to[1]) + 00238 (from[2]-to[2])*(from[2]-to[2])) < 1e-20 ) { 00239 degenerate_cylinders++; 00240 return; 00241 } 00242 00243 // write_materials(); 00244 00245 fprintf(outfile, "VMD_cylinder(<%g,%g,%g>,<%g,%g,%g>", 00246 from[0], from[1], -from[2], to[0], to[1], -to[2]); 00247 fprintf(outfile, "%.4f,rgbt<%.3f,%.3f,%.3f,%.3f>,%d)\n", 00248 radius, matData[colorIndex][0], matData[colorIndex][1], 00249 matData[colorIndex][2], 1 - mat_opacity, !filled); 00250 } 00251 00252 // draw a cone 00253 void POV3DisplayDevice::cone(float *a, float *b, float r, int /* resolution */) { 00254 float from[3], to[3]; 00255 float radius; 00256 00257 // transform the world coordinates 00258 (transMat.top()).multpoint3d(a, from); 00259 (transMat.top()).multpoint3d(b, to); 00260 radius = scale_radius(r); 00261 00262 // check for degenerate cylinders 00263 if ( ((from[0]-to[0])*(from[0]-to[0]) + 00264 (from[1]-to[1])*(from[1]-to[1]) + 00265 (from[2]-to[2])*(from[2]-to[2])) < 1e-20 ) { 00266 degenerate_cones++; 00267 return; 00268 } 00269 00270 // write_materials(); 00271 00272 // Draw the cone 00273 fprintf(outfile, "VMD_cone (<%g,%g,%g>,<%g,%g,%g>,%.4f,", 00274 from[0], from[1], -from[2], to[0], to[1], -to[2], radius); 00275 fprintf(outfile, "rgbt<%.3f,%.3f,%.3f,%.3f>)\n", 00276 matData[colorIndex][0], matData[colorIndex][1], matData[colorIndex][2], 00277 1 - mat_opacity); 00278 } 00279 00280 // draw a triangle using the current color 00281 // XXX - POV-Ray doesn't support indexed color for triangles -- we need to 00282 // use an RGB triple. Here we just use the same RGB triple for each vertex 00283 // and call tricolor. 00284 void POV3DisplayDevice::triangle(const float *a, const float *b, const float *c, 00285 const float *n1, const float *n2, const float *n3) { 00286 float c1[3], c2[3], c3[3]; 00287 00288 memcpy(c1, matData[colorIndex], 3 * sizeof(float)); 00289 memcpy(c2, matData[colorIndex], 3 * sizeof(float)); 00290 memcpy(c3, matData[colorIndex], 3 * sizeof(float)); 00291 00292 tricolor(a, b, c, n1, n2, n3, c1, c2, c3); 00293 return; 00294 } 00295 00296 // draw triangle with per-vertex colors 00297 void POV3DisplayDevice::tricolor(const float * xyz1, const float * xyz2, const float * xyz3, 00298 const float * n1, const float * n2, const float * n3, 00299 const float *c1, const float *c2, const float *c3) { 00300 float vec1[3], vec2[3], vec3[3], norm1[3], norm2[3], norm3[3]; 00301 float leg1[3], leg2[3], trinorm[3], ang1, ang2, ang3; 00302 00303 // transform the world coordinates 00304 (transMat.top()).multpoint3d(xyz1, vec1); 00305 (transMat.top()).multpoint3d(xyz2, vec2); 00306 (transMat.top()).multpoint3d(xyz3, vec3); 00307 00308 // and the normals 00309 (transMat.top()).multnorm3d(n1, norm1); 00310 (transMat.top()).multnorm3d(n2, norm2); 00311 (transMat.top()).multnorm3d(n3, norm3); 00312 00313 // write_materials(); 00314 00315 // Don't write degenerate triangles -- those with all normals more than 90 00316 // degrees from triangle normal or its inverse. 00317 vec_sub(leg1, vec2, vec1); 00318 vec_sub(leg2, vec3, vec1); 00319 cross_prod(trinorm, leg1, leg2); 00320 ang1 = dot_prod(trinorm, norm1); 00321 ang2 = dot_prod(trinorm, norm2); 00322 ang3 = dot_prod(trinorm, norm3); 00323 if ( ((ang1 >= 0.0) || (ang2 >= 0.0) || (ang3 >= 0.0)) && 00324 ((ang1 <= 0.0) || (ang2 <= 0.0) || (ang3 <= 0.0)) ) { 00325 degenerate_triangles++; 00326 return; 00327 } 00328 00329 // If all verticies have the same color, don't bother with per-vertex 00330 // coloring 00331 if ( (c1[0] == c2[0]) && (c1[0] == c3[0]) && 00332 (c1[1] == c2[1]) && (c1[1] == c3[1]) && 00333 (c1[2] == c2[2]) && (c1[2] == c3[2]) ) { 00334 fprintf(outfile, "VMD_triangle("); 00335 fprintf(outfile, "<%.8g,%.8g,%.8g>,<%.8g,%.8g,%.8g>,<%.8g,%.8g,%.8g>,", 00336 vec1[0], vec1[1], -vec1[2], vec2[0], vec2[1], -vec2[2], 00337 vec3[0], vec3[1], -vec3[2]); 00338 fprintf(outfile, "<%.8g,%.8g,%.8g>,<%.8g,%.8g,%.8g>,<%.8g,%.8g,%.8g>,", 00339 norm1[0], norm1[1], -norm1[2], norm2[0], norm2[1], -norm2[2], 00340 norm3[0], norm3[1], -norm3[2]); 00341 fprintf(outfile, "rgbt<%.3f,%.3f,%.3f,%.3f>)\n", 00342 c1[0], c1[1], c1[2], 1 - mat_opacity); 00343 } 00344 else { 00345 fprintf(outfile, "VMD_tricolor("); 00346 fprintf(outfile, "<%.8g,%.8g,%.8g>,<%.8g,%.8g,%.8g>,<%.8g,%.8g,%.8g>,", 00347 vec1[0], vec1[1], -vec1[2], vec2[0], vec2[1], -vec2[2], 00348 vec3[0], vec3[1], -vec3[2]); 00349 fprintf(outfile, "<%.8g,%.8g,%.8g>,<%.8g,%.8g,%.8g>,<%.8g,%.8g,%.8g>,", 00350 norm1[0], norm1[1], -norm1[2], norm2[0], norm2[1], -norm2[2], 00351 norm3[0], norm3[1], -norm3[2]); 00352 fprintf(outfile, "rgbt<%.3f,%.3f,%.3f,%.3f>,rgbt<%.3f,%.3f,%.3f,%.3f>,rgbt<%.3f,%.3f,%.3f,%.3f>)\n", 00353 c1[0], c1[1], c1[2], 1 - mat_opacity, c2[0], c2[1], c2[2], 00354 1 - mat_opacity, c3[0], c3[1], c3[2], 1 - mat_opacity); 00355 } 00356 } 00357 00358 #if 1 00359 // Draw a triangle mesh as a mesh2 POV-Ray object 00360 void POV3DisplayDevice::trimesh_c4n3v3(int numverts, float *cnv, 00361 int numfacets, int *facets) { 00362 int i; 00363 00364 // write_materials(); 00365 00366 if (clip_on[2]) { 00367 fprintf(outfile, "intersection {\n"); 00368 } 00369 fprintf(outfile, "mesh2 {\n"); 00370 00371 // Print the Vertex Vectors 00372 fprintf(outfile, " vertex_vectors {\n"); 00373 fprintf(outfile, " %d,\n", numverts); 00374 for (i=0; i<numverts; i++) { 00375 int ind = i * 10; 00376 float vtmp[3]; 00377 transMat.top().multpoint3d(cnv + ind + 7, vtmp); 00378 #if defined(POVRAY_BRAIN_DAMAGE_WORKAROUND) 00379 vtmp[0] *= POVRAY_SCALEHACK; 00380 vtmp[1] *= POVRAY_SCALEHACK; 00381 vtmp[2] *= POVRAY_SCALEHACK; 00382 #endif 00383 fprintf(outfile, " <%.4f,%.4f,%.4f>,\n", vtmp[0], vtmp[1], -vtmp[2]); 00384 } 00385 fprintf(outfile, " }\n"); 00386 00387 // Print the Normal Vectors 00388 fprintf(outfile, " normal_vectors {\n"); 00389 fprintf(outfile, " %d,\n", numverts); 00390 for (i=0; i<numverts; i++) { 00391 int ind = i * 10; 00392 float ntmp[3]; 00393 transMat.top().multnorm3d(cnv + ind + 4, ntmp); 00394 fprintf(outfile, " <%.4f,%.4f,%.4f>,\n", ntmp[0], ntmp[1], -ntmp[2]); 00395 } 00396 fprintf(outfile, " }\n"); 00397 00398 // Print the Texture List 00399 fprintf(outfile, " texture_list {\n"); 00400 fprintf(outfile, " %d,\n", numverts); 00401 for (i=0; i<numverts; i++) { 00402 int ind = i * 10; 00403 float *rgb = cnv + ind; 00404 fprintf(outfile, " VMDC(<%.3f,%.3f,%.3f,%.3f>)\n", 00405 rgb[0], rgb[1], rgb[2], 1 - mat_opacity); 00406 } 00407 fprintf(outfile, " }\n"); 00408 00409 // Face Indices 00410 fprintf(outfile, " face_indices {\n"); 00411 fprintf(outfile, " %d\n", numfacets); 00412 for (i = 0; i < numfacets; i++) { 00413 int ind = i * 3; 00414 00415 fprintf(outfile, " <%d,%d,%d>,%d,%d,%d\n", 00416 facets[ind], facets[ind + 1], facets[ind + 2], 00417 facets[ind], facets[ind + 1], facets[ind + 2]); 00418 } 00419 fprintf(outfile, " }\n"); 00420 00421 // Object Modifiers 00422 fprintf(outfile, " inside_vector <0, 0, 1>\n"); 00423 if (clip_on[1]) { 00424 #if defined(POVRAY_BRAIN_DAMAGE_WORKAROUND) 00425 fprintf(outfile, " clipped_by { VMD_scaledclip[1] }\n"); 00426 #else 00427 fprintf(outfile, " clipped_by { VMD_clip[1] }\n"); 00428 #endif 00429 } 00430 if (!shadows_enabled()) 00431 fprintf(outfile, " no_shadow\n"); 00432 00433 #if defined(POVRAY_BRAIN_DAMAGE_WORKAROUND) 00434 Matrix4 hackmatrix; 00435 hackmatrix.identity(); 00436 hackmatrix.scale(1.0f / POVRAY_SCALEHACK); 00437 const float *trans = hackmatrix.mat; 00438 fprintf(outfile, "matrix < \n"); 00439 fprintf(outfile, " %f, %f, %f,\n", trans[ 0], trans[ 1], trans[ 2]); 00440 fprintf(outfile, " %f, %f, %f,\n", trans[ 4], trans[ 5], trans[ 6]); 00441 fprintf(outfile, " %f, %f, %f,\n", trans[ 8], trans[ 9], trans[10]); 00442 fprintf(outfile, " %f, %f, %f \n", trans[12], trans[13], trans[14]); 00443 fprintf(outfile, "> "); 00444 #endif 00445 00446 fprintf(outfile, "}\n"); 00447 00448 if (clip_on[2]) { 00449 fprintf(outfile, " VMD_clip[2]\n"); 00450 if (!shadows_enabled()) 00451 fprintf(outfile, " no_shadow\n"); 00452 fprintf(outfile, "}\n"); 00453 } 00454 } 00455 00456 #else 00457 00458 // Draw a triangle mesh as a mesh2 POV-Ray object 00459 void POV3DisplayDevice::trimesh_c4n3v3(int numverts, float *cnv, 00460 int numfacets, int *facets) { 00461 float (*vert)[3], (*norm)[3], (*color)[3]; 00462 int i, ind, v0, v1, v2, *c_index, curr_index; 00463 00464 // write_materials(); 00465 00466 if (clip_on[2]) { 00467 fprintf(outfile, "intersection {\n"); 00468 } 00469 fprintf(outfile, "mesh2 {\n"); 00470 00471 // Read the mesh, storing vertex coordinates, normals, and (unique) colors 00472 // XXX - this can use a *lot* of memory, but not as much as POV will when 00473 // parsing the resulting scene file. 00474 vert = new float[numfacets * 3][3]; 00475 norm = new float[numfacets * 3][3]; 00476 color = new float[numfacets * 3][3]; 00477 c_index = new int[numfacets * 3]; 00478 curr_index = -1; 00479 00480 float prev_color[3] = { -1, -1, -1 }; 00481 for (i = 0; i < numfacets; i++) { 00482 ind = i * 3; 00483 v0 = facets[ind ] * 10; 00484 v1 = facets[ind + 1] * 10; 00485 v2 = facets[ind + 2] * 10; 00486 00487 // transform the verticies and store them in the array 00488 transMat.top().multpoint3d(cnv + v0 + 7, vert[ind ]); 00489 transMat.top().multpoint3d(cnv + v1 + 7, vert[ind + 1]); 00490 transMat.top().multpoint3d(cnv + v2 + 7, vert[ind + 2]); 00491 00492 // transform the normals and store them in the array 00493 transMat.top().multnorm3d(cnv + v0 + 4, norm[ind ]); 00494 transMat.top().multnorm3d(cnv + v1 + 4, norm[ind + 1]); 00495 transMat.top().multnorm3d(cnv + v2 + 4, norm[ind + 2]); 00496 00497 #if defined(POVRAY_BRAIN_DAMAGE_WORKAROUND) 00498 vert[ind ][0] *= POVRAY_SCALEHACK; 00499 vert[ind ][1] *= POVRAY_SCALEHACK; 00500 vert[ind ][2] *= POVRAY_SCALEHACK; 00501 vert[ind + 1][0] *= POVRAY_SCALEHACK; 00502 vert[ind + 1][1] *= POVRAY_SCALEHACK; 00503 vert[ind + 1][2] *= POVRAY_SCALEHACK; 00504 vert[ind + 2][0] *= POVRAY_SCALEHACK; 00505 vert[ind + 2][1] *= POVRAY_SCALEHACK; 00506 vert[ind + 2][2] *= POVRAY_SCALEHACK; 00507 #endif 00508 00509 // Only store a color if it's different than the previous color, 00510 // this saves a lot of space for large triangle meshes. 00511 if (memcmp(prev_color, (cnv + v0), 3*sizeof(float)) != 0) { 00512 curr_index++; 00513 memcpy(color[curr_index], (cnv + v0), 3*sizeof(float)); 00514 memcpy(prev_color, (cnv + v0), 3*sizeof(float)); 00515 } 00516 c_index[ind] = curr_index; 00517 00518 if (memcmp(prev_color, (cnv + v1), 3*sizeof(float)) != 0) { 00519 curr_index++; 00520 memcpy(color[curr_index], (cnv + v1), 3*sizeof(float)); 00521 memcpy(prev_color, (cnv + v1), 3*sizeof(float)); 00522 } 00523 c_index[ind+1] = curr_index; 00524 00525 if (memcmp(prev_color, (cnv + v2), 3*sizeof(float)) != 0) { 00526 curr_index++; 00527 memcpy(color[curr_index], (cnv + v2), 3*sizeof(float)); 00528 memcpy(prev_color, (cnv + v2), 3*sizeof(float)); 00529 } 00530 c_index[ind+2] = curr_index; 00531 } 00532 00533 // Print the Vertex Vectors 00534 fprintf(outfile, " vertex_vectors {\n"); 00535 fprintf(outfile, " %d,\n", numfacets * 3); 00536 for (i = 0; i < (numfacets * 3); i++) { 00537 fprintf(outfile, " <%.4f,%.4f,%.4f>,\n", 00538 vert[i][0], vert[i][1], -vert[i][2]); 00539 } 00540 fprintf(outfile, " }\n"); 00541 00542 // Print the Normal Vectors 00543 fprintf(outfile, " normal_vectors {\n"); 00544 fprintf(outfile, " %d,\n", numfacets * 3); 00545 for (i = 0; i < (numfacets * 3); i++) { 00546 fprintf(outfile, " <%.4f,%.4f,%.4f>,\n", 00547 norm[i][0], norm[i][1], -norm[i][2]); 00548 } 00549 fprintf(outfile, " }\n"); 00550 00551 // Print the Texture List 00552 fprintf(outfile, " texture_list {\n"); 00553 fprintf(outfile, " %d,\n", curr_index+1); 00554 for (i = 0; i <= curr_index; i++) { 00555 fprintf(outfile, " VMDC(<%.3f,%.3f,%.3f,%.3f>)\n", 00556 color[i][0], color[i][1], color[i][2], 1 - mat_opacity); 00557 } 00558 fprintf(outfile, " }\n"); 00559 00560 // Face Indices 00561 fprintf(outfile, " face_indices {\n"); 00562 fprintf(outfile, " %d\n", numfacets); 00563 for (i = 0; i < numfacets; i++) { 00564 ind = i * 3; 00565 00566 // Print three vertex/normal and color indicies. 00567 if ((c_index[ind] == c_index[ind+1]) && (c_index[ind] == c_index[ind+2])) { 00568 // Only one color index is required if the triangle doesn't use 00569 // per-vertex shading 00570 fprintf(outfile, " <%d,%d,%d>,%d\n", 00571 ind, ind + 1, ind + 2, c_index[ind]); 00572 } 00573 else { 00574 fprintf(outfile, " <%d,%d,%d>,%d,%d,%d\n", 00575 ind, ind + 1, ind + 2, 00576 c_index[ind], c_index[ind+1], c_index[ind+2]); 00577 } 00578 } 00579 fprintf(outfile, " }\n"); 00580 00581 // Object Modifiers 00582 fprintf(outfile, " inside_vector <0, 0, 1>\n"); 00583 if (clip_on[1]) { 00584 #if defined(POVRAY_BRAIN_DAMAGE_WORKAROUND) 00585 fprintf(outfile, " clipped_by { VMD_scaledclip[1] }\n"); 00586 #else 00587 fprintf(outfile, " clipped_by { VMD_clip[1] }\n"); 00588 #endif 00589 } 00590 if (!shadows_enabled()) 00591 fprintf(outfile, " no_shadow\n"); 00592 00593 #if defined(POVRAY_BRAIN_DAMAGE_WORKAROUND) 00594 Matrix4 hackmatrix; 00595 hackmatrix.identity(); 00596 hackmatrix.scale(1.0f / POVRAY_SCALEHACK); 00597 const float *trans = hackmatrix.mat; 00598 fprintf(outfile, "matrix < \n"); 00599 fprintf(outfile, " %f, %f, %f,\n", trans[ 0], trans[ 1], trans[ 2]); 00600 fprintf(outfile, " %f, %f, %f,\n", trans[ 4], trans[ 5], trans[ 6]); 00601 fprintf(outfile, " %f, %f, %f,\n", trans[ 8], trans[ 9], trans[10]); 00602 fprintf(outfile, " %f, %f, %f \n", trans[12], trans[13], trans[14]); 00603 fprintf(outfile, "> "); 00604 #endif 00605 00606 fprintf(outfile, "}\n"); 00607 00608 if (clip_on[2]) { 00609 fprintf(outfile, " VMD_clip[2]\n"); 00610 if (!shadows_enabled()) 00611 fprintf(outfile, " no_shadow\n"); 00612 fprintf(outfile, "}\n"); 00613 } 00614 00615 delete [] vert; 00616 delete [] norm; 00617 delete [] color; 00618 delete [] c_index; 00619 } 00620 #endif 00621 00622 00623 // Draw a triangle mesh as a mesh2 POV-Ray object 00624 void POV3DisplayDevice::trimesh_c4u_n3b_v3f(unsigned char *c, signed char *n, 00625 float *v, int numfacets) { 00626 int i; 00627 int numverts = 3*numfacets; 00628 00629 const float ci2f = 1.0f / 255.0f; // used for uchar2float and normal conv 00630 const float cn2f = 1.0f / 127.5f; 00631 00632 // write_materials(); 00633 00634 if (clip_on[2]) { 00635 fprintf(outfile, "intersection {\n"); 00636 } 00637 fprintf(outfile, "mesh2 {\n"); 00638 00639 // Read the mesh storing a list of unique colors 00640 float (*color)[3] = new float[numverts][3]; 00641 int *c_index = new int[numverts]; 00642 int curr_index = -1; 00643 float prev_color[3] = { -1, -1, -1 }; 00644 for (i = 0; i < numverts; i++) { 00645 // Only store a color if it's different than the previous color, 00646 // this saves a lot of space for large triangle meshes. 00647 float ctmp[3]; 00648 int ind = i * 4; 00649 ctmp[0] = c[ind ] * ci2f; 00650 ctmp[1] = c[ind+1] * ci2f; 00651 ctmp[2] = c[ind+2] * ci2f; 00652 if (memcmp(prev_color, ctmp, 3*sizeof(float)) != 0) { 00653 curr_index++; 00654 memcpy(color[curr_index], ctmp, 3*sizeof(float)); 00655 memcpy(prev_color, ctmp, 3*sizeof(float)); 00656 } 00657 c_index[i] = curr_index; 00658 } 00659 00660 // Print the Vertex Vectors 00661 fprintf(outfile, " vertex_vectors {\n"); 00662 fprintf(outfile, " %d,\n", numverts); 00663 for (i = 0; i < numverts; i++) { 00664 int ind = i * 3; 00665 float vtmp[3]; 00666 transMat.top().multpoint3d(v+ind, vtmp); 00667 00668 #if defined(POVRAY_BRAIN_DAMAGE_WORKAROUND) 00669 vtmp[0] *= POVRAY_SCALEHACK; 00670 vtmp[1] *= POVRAY_SCALEHACK; 00671 vtmp[2] *= POVRAY_SCALEHACK; 00672 #endif 00673 00674 fprintf(outfile, " <%.4f,%.4f,%.4f>,\n", vtmp[0], vtmp[1], -vtmp[2]); 00675 } 00676 fprintf(outfile, " }\n"); 00677 00678 // Print the Normal Vectors 00679 fprintf(outfile, " normal_vectors {\n"); 00680 fprintf(outfile, " %d,\n", numverts); 00681 for (i = 0; i < numverts; i++) { 00682 int ind = i * 3; 00683 float ntmp[3], ntmp2[3]; 00684 00685 // conversion from GLbyte format, Table 2.6, p. 44 of OpenGL spec 1.2.1 00686 // float = (2c+1)/(2^8-1) 00687 ntmp[0] = n[ind ] * cn2f + ci2f; 00688 ntmp[1] = n[ind+1] * cn2f + ci2f; 00689 ntmp[2] = n[ind+2] * cn2f + ci2f; 00690 00691 // transform the normals and store them in the array 00692 transMat.top().multnorm3d(ntmp, ntmp2); 00693 fprintf(outfile, " <%.3f,%.3f,%.3f>,\n", ntmp2[0], ntmp2[1], -ntmp[2]); 00694 } 00695 fprintf(outfile, " }\n"); 00696 00697 // Print the Texture List 00698 fprintf(outfile, " texture_list {\n"); 00699 fprintf(outfile, " %d,\n", curr_index+1); 00700 for (i = 0; i <= curr_index; i++) { 00701 fprintf(outfile, " VMDC(<%.3f,%.3f,%.3f,%.3f>)\n", 00702 color[i][0], color[i][1], color[i][2], 1 - mat_opacity); 00703 } 00704 fprintf(outfile, " }\n"); 00705 00706 // Face Indices 00707 fprintf(outfile, " face_indices {\n"); 00708 fprintf(outfile, " %d\n", numfacets); 00709 for (i = 0; i < numfacets; i++) { 00710 int ind = i * 3; 00711 00712 // Print three vertex/normal and color indicies. 00713 if ((c_index[ind] == c_index[ind+1]) && (c_index[ind] == c_index[ind+2])) { 00714 // Only one color index is required if the triangle doesn't use 00715 // per-vertex shading 00716 fprintf(outfile, " <%d,%d,%d>,%d\n", 00717 ind, ind + 1, ind + 2, c_index[ind]); 00718 } 00719 else { 00720 fprintf(outfile, " <%d,%d,%d>,%d,%d,%d\n", 00721 ind, ind + 1, ind + 2, 00722 c_index[ind], c_index[ind+1], c_index[ind+2]); 00723 } 00724 } 00725 fprintf(outfile, " }\n"); 00726 00727 // Object Modifiers 00728 fprintf(outfile, " inside_vector <0, 0, 1>\n"); 00729 if (clip_on[1]) { 00730 #if defined(POVRAY_BRAIN_DAMAGE_WORKAROUND) 00731 fprintf(outfile, " clipped_by { VMD_scaledclip[1] }\n"); 00732 #else 00733 fprintf(outfile, " clipped_by { VMD_clip[1] }\n"); 00734 #endif 00735 } 00736 if (!shadows_enabled()) 00737 fprintf(outfile, " no_shadow\n"); 00738 00739 #if defined(POVRAY_BRAIN_DAMAGE_WORKAROUND) 00740 Matrix4 hackmatrix; 00741 hackmatrix.identity(); 00742 hackmatrix.scale(1.0f / POVRAY_SCALEHACK); 00743 const float *trans = hackmatrix.mat; 00744 fprintf(outfile, "matrix < \n"); 00745 fprintf(outfile, " %f, %f, %f,\n", trans[ 0], trans[ 1], trans[ 2]); 00746 fprintf(outfile, " %f, %f, %f,\n", trans[ 4], trans[ 5], trans[ 6]); 00747 fprintf(outfile, " %f, %f, %f,\n", trans[ 8], trans[ 9], trans[10]); 00748 fprintf(outfile, " %f, %f, %f \n", trans[12], trans[13], trans[14]); 00749 fprintf(outfile, "> "); 00750 #endif 00751 00752 fprintf(outfile, "}\n"); 00753 00754 if (clip_on[2]) { 00755 fprintf(outfile, " VMD_clip[2]\n"); 00756 if (!shadows_enabled()) 00757 fprintf(outfile, " no_shadow\n"); 00758 fprintf(outfile, "}\n"); 00759 } 00760 00761 delete [] color; 00762 delete [] c_index; 00763 } 00764 00765 00766 // Draw a collection of triangle strips as a mesh2 POV-Ray object 00767 void POV3DisplayDevice::tristrip(int numverts, const float *cnv, 00768 int numstrips, const int *vertsperstrip, 00769 const int *facets) { 00770 int strip, v, i, numfacets; 00771 float (*vert)[3], (*norm)[3], (*color)[3]; 00772 00773 // POV-Ray does use triangle winding-order to determine the orientation of 00774 // a triangle. Although the default triangle macro doesn't make use of 00775 // this, the interior_texture property can be specified to give 00776 // back-facing triangles a different texture. 00777 int stripaddr[2][3] = { {0, 1, 2}, {1, 0, 2} }; 00778 00779 // write_materials(); 00780 00781 if (clip_on[2]) { 00782 fprintf(outfile, "intersection {\n"); 00783 } 00784 fprintf(outfile, "mesh2 {\n"); 00785 00786 // Read the mesh, storing vertex coordinates, normals, and colors 00787 // XXX - this can use a *lot* of memory, but not as much as POV will when 00788 // parsing the resulting scene file. 00789 vert = new float[numverts][3]; 00790 norm = new float[numverts][3]; 00791 color = new float[numverts][3]; 00792 00793 for (i = 0; i < numverts; i++) { 00794 transMat.top().multpoint3d(cnv + i*10 + 7, vert[i]); 00795 transMat.top().multnorm3d(cnv + i*10 + 4, norm[i]); 00796 00797 #if defined(POVRAY_BRAIN_DAMAGE_WORKAROUND) 00798 vert[i][0] *= POVRAY_SCALEHACK; 00799 vert[i][1] *= POVRAY_SCALEHACK; 00800 vert[i][2] *= POVRAY_SCALEHACK; 00801 #endif 00802 00803 memcpy(color[i], cnv + i*10, 3*sizeof(float)); 00804 } 00805 00806 // Print the Vertex Vectors 00807 fprintf(outfile, " vertex_vectors {\n"); 00808 fprintf(outfile, " %d,\n", numverts); 00809 for (i = 0; i < numverts; i++) { 00810 fprintf(outfile, " <%.4f,%.4f,%.4f>,\n", 00811 vert[i][0], vert[i][1], -vert[i][2]); 00812 } 00813 fprintf(outfile, " }\n"); 00814 00815 // Print the Normal Vectors 00816 fprintf(outfile, " normal_vectors {\n"); 00817 fprintf(outfile, " %d,\n", numverts); 00818 for (i = 0; i < numverts; i++) { 00819 fprintf(outfile, " <%.4f,%.4f,%.4f>,\n", 00820 norm[i][0], norm[i][1], -norm[i][2]); 00821 } 00822 fprintf(outfile, " }\n"); 00823 00824 // Print the Texture List 00825 fprintf(outfile, " texture_list {\n"); 00826 fprintf(outfile, " %d,\n", numverts); 00827 for (i = 0; i < numverts; i++) { 00828 fprintf(outfile, " VMDC(<%.3f,%.3f,%.3f,%.3f>)\n", 00829 color[i][0], color[i][1], color[i][2], 1 - mat_opacity); 00830 } 00831 fprintf(outfile, " }\n"); 00832 00833 // Find the number of facets 00834 numfacets = 0; 00835 for (strip = 0; strip < numstrips; strip++) { 00836 numfacets += (vertsperstrip[strip] - 2); 00837 } 00838 00839 // Print the Face Indices 00840 v = 0; 00841 fprintf(outfile, " face_indices {\n"); 00842 fprintf(outfile, " %d\n", numfacets); 00843 for (strip = 0; strip < numstrips; strip++) { 00844 for (i = 0; i < (vertsperstrip[strip] - 2); i++) { 00845 fprintf(outfile, " <%d,%d,%d>,%d,%d,%d\n", 00846 facets[v + (stripaddr[i & 0x01][0])], 00847 facets[v + (stripaddr[i & 0x01][1])], 00848 facets[v + (stripaddr[i & 0x01][2])], 00849 facets[v + (stripaddr[i & 0x01][0])], 00850 facets[v + (stripaddr[i & 0x01][1])], 00851 facets[v + (stripaddr[i & 0x01][2])] ); 00852 v++; 00853 } 00854 v += 2; 00855 } 00856 fprintf(outfile, " }\n"); 00857 00858 // Object Modifiers 00859 fprintf(outfile, " inside_vector <0, 0, 1>\n"); 00860 if (clip_on[1]) { 00861 #if defined(POVRAY_BRAIN_DAMAGE_WORKAROUND) 00862 fprintf(outfile, " clipped_by { VMD_scaledclip[1] }\n"); 00863 #else 00864 fprintf(outfile, " clipped_by { VMD_clip[1] }\n"); 00865 #endif 00866 } 00867 00868 #if defined(POVRAY_BRAIN_DAMAGE_WORKAROUND) 00869 Matrix4 hackmatrix; 00870 hackmatrix.identity(); 00871 hackmatrix.scale(1.0f / POVRAY_SCALEHACK); 00872 const float *trans = hackmatrix.mat; 00873 fprintf(outfile, "matrix < \n"); 00874 fprintf(outfile, " %f, %f, %f,\n", trans[ 0], trans[ 1], trans[ 2]); 00875 fprintf(outfile, " %f, %f, %f,\n", trans[ 4], trans[ 5], trans[ 6]); 00876 fprintf(outfile, " %f, %f, %f,\n", trans[ 8], trans[ 9], trans[10]); 00877 fprintf(outfile, " %f, %f, %f \n", trans[12], trans[13], trans[14]); 00878 fprintf(outfile, "> "); 00879 #endif 00880 00881 if (!shadows_enabled()) 00882 fprintf(outfile, " no_shadow\n"); 00883 fprintf(outfile, "}\n"); 00884 00885 if (clip_on[2]) { 00886 fprintf(outfile, " VMD_clip[2]\n"); 00887 if (!shadows_enabled()) 00888 fprintf(outfile, " no_shadow\n"); 00889 fprintf(outfile, "}\n"); 00890 } 00891 00892 delete [] vert; 00893 delete [] norm; 00894 delete [] color; 00895 } 00896 00897 // display a comment 00898 void POV3DisplayDevice::comment(const char *s) { 00899 fprintf (outfile, "// %s\n", s); 00900 } 00901 00903 00904 void POV3DisplayDevice::write_header() { 00905 long myXsize; 00906 float zDirection; 00907 00908 // cross-eyes and side-by-side stereo split the screen; so we need 00909 // to cut xSize in half in this case 00910 myXsize = xSize; 00911 //if (inStereo == OPENGL_STEREO_SIDE) 00912 // myXsize /= 2; 00913 // if (inStereo == OPENGL_STEREO_ABOVEBELOW) 00914 // myXsize *= 2; 00915 fprintf(outfile, "// \n"); 00916 fprintf(outfile, "// Molecular graphics export from VMD %s\n", VMDVERSION); 00917 fprintf(outfile, "// http://www.ks.uiuc.edu/Research/vmd/\n"); 00918 fprintf(outfile, "// Requires POV-Ray 3.5 or later\n"); 00919 fprintf(outfile, "// \n"); 00920 00921 fprintf(outfile, "// POV 3.x input script : %s \n", my_filename); 00922 fprintf(outfile, "// try povray +W%ld +H%ld -I%s ", myXsize, ySize, my_filename); 00923 fprintf(outfile, "-O%s.tga +P +X +A +FT +C", my_filename); 00924 00925 // need to disable the vista buffer when stereo rendering 00926 if (whichEye != DisplayDevice::NOSTEREO) fprintf(outfile, " -UV"); 00927 fprintf(outfile, "\n"); 00928 00929 #if 0 00930 msgInfo << "Default povray command line should be:" << sendmsg; 00931 00932 msgInfo << " povray +W" << myXsize << " +H" << ySize << " -I" << my_filename 00933 << " -O" << my_filename << ".tga +P +X +A +FT +C"; 00934 if (whichEye != DisplayDevice::NOSTEREO) msgInfo << " -UV"; 00935 msgInfo << sendmsg; 00936 #endif 00937 00938 // Warn the user if the plugin was compiled for a different version of POV 00939 // than they're using 00940 fprintf(outfile, "#if (version < 3.5) \n"); 00941 fprintf(outfile, "#error \"VMD POV3DisplayDevice has been compiled for POV-Ray 3.5 or above.\\nPlease upgrade POV-Ray or recompile VMD.\"\n"); 00942 fprintf(outfile, "#end \n"); 00943 00944 // Initialize POV-Ray state variables 00945 fprintf(outfile, "#declare VMD_clip_on=array[3] {0, 0, 0};\n"); 00946 fprintf(outfile, "#declare VMD_clip=array[3];\n"); 00947 fprintf(outfile, "#declare VMD_scaledclip=array[3];\n"); 00948 fprintf(outfile, "#declare VMD_line_width=%.4f;\n", 00949 ((float)lineWidth)*DEFAULT_RADIUS); 00950 00951 // 00952 // Macros for VMD-like graphic primitives in POV. 00953 // 00954 00955 // Color/Texture: save space when emitting texture lines for mesh2 primitives 00956 fprintf(outfile, "#macro VMDC ( C1 )\n"); 00957 fprintf(outfile, " texture { pigment { rgbt C1 }}\n"); 00958 fprintf(outfile, "#end\n"); 00959 00960 // Point: can be quickly approximated as spheres with no shading. 00961 fprintf(outfile, "#macro VMD_point (P1, R1, C1)\n"); 00962 fprintf(outfile, " #local T = texture { finish { ambient 1.0 diffuse 0.0 phong 0.0 specular 0.0 } pigment { C1 } }\n"); 00963 fprintf(outfile, " #if(VMD_clip_on[2])\n"); 00964 fprintf(outfile, " intersection {\n"); 00965 fprintf(outfile, " sphere {P1, R1 texture {T} #if(VMD_clip_on[1]) clipped_by {VMD_clip[1]} #end %s}\n", (shadows_enabled()) ? "" : "no_shadow"); 00966 fprintf(outfile, " VMD_clip[2]\n"); 00967 fprintf(outfile, " }\n #else\n"); 00968 fprintf(outfile, " sphere {P1, R1 texture {T} #if(VMD_clip_on[1]) clipped_by {VMD_clip[1]} #end %s}\n", (shadows_enabled()) ? "" : "no_shadow"); 00969 fprintf(outfile, " #end\n"); 00970 fprintf(outfile, "#end\n"); 00971 00972 // Line: can be quickly approximated as cylinders with no shading 00973 fprintf(outfile, "#macro VMD_line (P1, P2, C1)\n"); 00974 fprintf(outfile, " #local T = texture { finish { ambient 1.0 diffuse 0.0 phong 0.0 specular 0.0 } pigment { C1 } }\n"); 00975 fprintf(outfile, " #if(VMD_clip_on[2])\n"); 00976 fprintf(outfile, " intersection {\n"); 00977 fprintf(outfile, " cylinder {P1, P2, VMD_line_width texture {T} #if(VMD_clip_on[1]) clipped_by {VMD_clip[1]} #end %s}\n", (shadows_enabled()) ? "" : "no_shadow"); 00978 fprintf(outfile, " VMD_clip[2]\n"); 00979 fprintf(outfile, " }\n #else\n"); 00980 fprintf(outfile, " cylinder {P1, P2, VMD_line_width texture {T} #if(VMD_clip_on[1]) clipped_by {VMD_clip[1]} #end %s}\n", (shadows_enabled()) ? "" : "no_shadow"); 00981 fprintf(outfile, " #end\n"); 00982 fprintf(outfile, "#end\n"); 00983 00984 // Sphere 00985 fprintf(outfile, "#macro VMD_sphere (P1, R1, C1)\n"); 00986 fprintf(outfile, " #local T = texture { pigment { C1 } }\n"); 00987 fprintf(outfile, " #if(VMD_clip_on[2])\n"); 00988 fprintf(outfile, " intersection {\n"); 00989 fprintf(outfile, " sphere {P1, R1 texture {T} #if(VMD_clip_on[1]) clipped_by {VMD_clip[1]} #end %s}\n", (shadows_enabled()) ? "" : "no_shadow"); 00990 fprintf(outfile, " VMD_clip[2]\n"); 00991 fprintf(outfile, " }\n #else\n"); 00992 fprintf(outfile, " sphere {P1, R1 texture {T} #if(VMD_clip_on[1]) clipped_by {VMD_clip[1]} #end %s}\n", (shadows_enabled()) ? "" : "no_shadow"); 00993 fprintf(outfile, " #end\n"); 00994 fprintf(outfile, "#end\n"); 00995 00996 // Cylinder: open iff O1 == 1 00997 fprintf(outfile, "#macro VMD_cylinder (P1, P2, R1, C1, O1)\n"); 00998 fprintf(outfile, " #local T = texture { pigment { C1 } }\n"); 00999 fprintf(outfile, " #if(VMD_clip_on[2])\n"); 01000 fprintf(outfile, " intersection {\n"); 01001 fprintf(outfile, " cylinder {P1, P2, R1 #if(O1) open #end texture {T} #if(VMD_clip_on[1]) clipped_by {VMD_clip[1]} #end %s}\n", (shadows_enabled()) ? "" : "no_shadow"); 01002 fprintf(outfile, " VMD_clip[2]\n"); 01003 fprintf(outfile, " }\n #else\n"); 01004 fprintf(outfile, " cylinder {P1, P2, R1 #if(O1) open #end texture {T} #if(VMD_clip_on[1]) clipped_by {VMD_clip[1]} #end %s}\n", (shadows_enabled()) ? "" : "no_shadow"); 01005 fprintf(outfile, " #end\n"); 01006 fprintf(outfile, "#end\n"); 01007 01008 // Cone: use the current lineWidth for the cap radius 01009 fprintf(outfile, "#macro VMD_cone (P1, P2, R1, C1)\n"); 01010 fprintf(outfile, " #local T = texture { pigment { C1 } }\n"); 01011 fprintf(outfile, " #if(VMD_clip_on[2])\n"); 01012 fprintf(outfile, " intersection {\n"); 01013 fprintf(outfile, " cone {P1, R1, P2, VMD_line_width texture {T} #if(VMD_clip_on[1]) clipped_by {VMD_clip[1]} #end %s}\n", (shadows_enabled()) ? "" : "no_shadow"); 01014 fprintf(outfile, " VMD_clip[2]\n"); 01015 fprintf(outfile, " }\n #else\n"); 01016 fprintf(outfile, " cone {P1, R1, P2, VMD_line_width texture {T} #if(VMD_clip_on[1]) clipped_by {VMD_clip[1]} #end %s}\n", (shadows_enabled()) ? "" : "no_shadow"); 01017 fprintf(outfile, " #end\n"); 01018 fprintf(outfile, "#end\n"); 01019 01020 // Triangle: single color, vertex normals 01021 // XXX - don't CSG clip triangles, behavior is undefined 01022 fprintf(outfile, "#macro VMD_triangle (P1, P2, P3, N1, N2, N3, C1)\n"); 01023 fprintf(outfile, " #local T = texture { pigment { C1 } }\n"); 01024 fprintf(outfile, " smooth_triangle {P1, N1, P2, N2, P3, N3 texture {T} #if(VMD_clip_on[1]) clipped_by {VMD_clip[1]} #end %s}\n", (shadows_enabled()) ? "" : "no_shadow"); 01025 fprintf(outfile, "#end\n"); 01026 01027 // Tricolor: vertex colors and normals 01028 // XXX - don't CSG clip triangles, behavior is undefined 01029 fprintf(outfile, "#macro VMD_tricolor (P1, P2, P3, N1, N2, N3, C1, C2, C3)\n"); 01030 fprintf(outfile, " #local NX = P2-P1;\n"); 01031 fprintf(outfile, " #local NY = P3-P1;\n"); 01032 fprintf(outfile, " #local NZ = vcross(NX, NY);\n"); 01033 fprintf(outfile, " #local T = texture { pigment {\n"); 01034 01035 // Create a color cube with the vertex colors at three corners 01036 fprintf(outfile, " average pigment_map {\n"); 01037 fprintf(outfile, " [1 gradient x color_map {[0 rgb 0] [1 C2*3]}]\n"); 01038 fprintf(outfile, " [1 gradient y color_map {[0 rgb 0] [1 C3*3]}]\n"); 01039 fprintf(outfile, " [1 gradient z color_map {[0 rgb 0] [1 C1*3]}]\n"); 01040 fprintf(outfile, " }\n"); 01041 01042 // Transform the cube so those corners match the triangle vertices 01043 fprintf(outfile, " matrix <1.01,0,1,0,1.01,1,0,0,1,-.002,-.002,-1>\n"); 01044 fprintf(outfile, " matrix <NX.x,NX.y,NX.z,NY.x,NY.y,NY.z,NZ.x,NZ.y,NZ.z,P1.x,P1.y,P1.z>\n"); 01045 fprintf(outfile, " } }\n"); 01046 01047 fprintf(outfile, " smooth_triangle {P1, N1, P2, N2, P3, N3 texture {T} #if(VMD_clip_on[1]) clipped_by {VMD_clip[1]} #end %s}\n", (shadows_enabled()) ? "" : "no_shadow"); 01048 fprintf(outfile, "#end\n"); 01049 01050 01051 // Camera position 01052 // POV uses a left-handed coordinate system 01053 // VMD uses right-handed, so z(pov) = -z(vmd). 01054 01055 switch (projection()) { 01056 01057 case DisplayDevice::ORTHOGRAPHIC: 01058 01059 fprintf(outfile, "camera {\n"); 01060 fprintf(outfile, " orthographic\n"); 01061 fprintf(outfile, " location <%.4f, %.4f, %.4f>\n", 01062 eyePos[0], eyePos[1], -eyePos[2]); 01063 fprintf(outfile, " look_at <%.4f, %.4f, %.4f>\n", 01064 eyeDir[0], eyeDir[1], -eyeDir[2]); 01065 fprintf(outfile, " up <0.0000, %.4f, 0.0000>\n", vSize / 2.0f); 01066 fprintf(outfile, " right <%.4f, 0.0000, 0.0000>\n", Aspect * vSize / 2.0f); 01067 fprintf(outfile, "}\n"); 01068 01069 break; 01070 01071 case DisplayDevice::PERSPECTIVE: 01072 default: 01073 01074 if (whichEye != DisplayDevice::NOSTEREO) { 01075 if (whichEye == DisplayDevice::LEFTEYE) 01076 fprintf(outfile, "// Stereo rendering enabled. Now rendering left eye.\n"); 01077 else 01078 fprintf(outfile, "// Stereo rendering enabled. Now rendering right eye.\n"); 01079 01080 fprintf(outfile, "// POV-Ray may give you a warning about non-perpendicular\n"); 01081 fprintf(outfile, "// camera vectors; this is a result of the stereo rendering.\n"); 01082 fprintf(outfile, "#warning \"You may ignore the following warning about " 01083 "nonperpendicular camera vectors.\"\n"); 01084 } 01085 01086 fprintf(outfile, "camera {\n"); 01087 fprintf(outfile, " up <0, %.4f, 0>\n", vSize); 01088 fprintf(outfile, " right <%.4f, 0, 0>\n", Aspect * vSize); 01089 fprintf(outfile, " location <%.4f, %.4f, %.4f>\n", 01090 eyePos[0], eyePos[1], -eyePos[2]); 01091 fprintf(outfile, " look_at <%.4f, %.4f, %.4f>\n", 01092 eyePos[0] + eyeDir[0], 01093 eyePos[1] + eyeDir[1], 01094 -(eyePos[2] + eyeDir[2])); 01095 01096 01097 // POV-Ray doesn't handle negative directions (i.e. when the image 01098 // plane is behind the viewpoint) well: the image should be mirrored 01099 // about both the x and y axes. We simulate this case by using a sky 01100 // vector. 01101 zDirection = eyePos[2] - zDist; 01102 if (zDirection < 0) { 01103 fprintf(outfile, " direction <%.4f, %.4f, %.4f>\n", 01104 -eyePos[0], -eyePos[1], -zDirection); 01105 fprintf(outfile, " sky <0, -1, 0>\n"); 01106 } 01107 else { 01108 fprintf(outfile, " direction <%.4f, %.4f, %.4f>\n", 01109 -eyePos[0], -eyePos[1], zDirection); 01110 } 01111 01112 01113 // render with depth of field, but only for perspective projection 01114 if (dof_enabled() && (projection() == DisplayDevice::PERSPECTIVE)) { 01115 msgInfo << "DoF focal blur enabled." << sendmsg; 01116 fprintf(outfile, " focal_point <%g, %g, %g>\n", 01117 eyePos[0] + eyeDir[0]*get_dof_focal_dist(), 01118 eyePos[1] + eyeDir[1]*get_dof_focal_dist(), 01119 -(eyePos[2] + eyeDir[2]*get_dof_focal_dist())); 01120 fprintf(outfile, " aperture %f\n", 01121 vSize * 4.0f * get_dof_focal_dist() / get_dof_fnumber()); 01122 fprintf(outfile, " blur_samples 100\n"); 01123 fprintf(outfile, " confidence 0.9\n"); 01124 fprintf(outfile, " variance 1/128\n"); 01125 } 01126 01127 fprintf(outfile, "}\n"); 01128 01129 break; 01130 01131 } // switch (projection()) 01132 01133 // Lights 01134 int i; 01135 for (i=0;i<DISP_LIGHTS;i++) { 01136 if (lightState[i].on) { 01137 // directional light source, as implemented in povray 3.5 01138 fprintf(outfile, "light_source { \n <%.4f, %.4f, %.4f> \n", 01139 lightState[i].pos[0], lightState[i].pos[1], 01140 -lightState[i].pos[2]); 01141 fprintf(outfile, " color rgb<%.3f, %.3f, %.3f> \n", 01142 lightState[i].color[0], lightState[i].color[1], 01143 lightState[i].color[2]); 01144 fprintf(outfile, " parallel \n point_at <0.0, 0.0, 0.0> \n}\n"); 01145 } 01146 } 01147 01148 01149 // background color 01150 fprintf(outfile, "background {\n color rgb<%.3f, %.3f, %.3f>\n}\n", 01151 backColor[0], backColor[1], backColor[2]); 01152 01153 // Specify background sky sphere if background gradient mode is enabled. 01154 if (backgroundmode == 1) { 01155 fprintf(outfile, "\n"); 01156 fprintf(outfile, "sky_sphere {\n"); 01157 fprintf(outfile, " pigment {\n"); 01158 fprintf(outfile, " gradient y\n"); 01159 fprintf(outfile, " color_map {\n"); 01160 fprintf(outfile, " [ 0.0 color rgb<%.3f, %.3f, %.3f> ]\n", 01161 backgradientbotcolor[0], backgradientbotcolor[1], backgradientbotcolor[2]); 01162 fprintf(outfile, " [ 1.0 color rgb<%.3f, %.3f, %.3f> ]\n", 01163 backgradienttopcolor[0], backgradienttopcolor[1], backgradienttopcolor[2]); 01164 fprintf(outfile, " }\n"); 01165 fprintf(outfile, " scale 2\n"); 01166 fprintf(outfile, " translate -1\n"); 01167 fprintf(outfile, " }\n"); 01168 fprintf(outfile, "}\n"); 01169 fprintf(outfile, "\n"); 01170 } 01171 01172 // depth-cueing (fog) 01173 if (cueingEnabled && (get_cue_density() >= 1e-4)) { 01174 fprintf(outfile, "fog {\n"); 01175 01176 switch (cueMode) { 01177 case CUE_EXP2: 01178 case CUE_LINEAR: 01179 case CUE_EXP: 01180 // XXX We use povray's exponential fog for all cases 01181 // since it doesn't currently support any other fog types yet. 01182 fprintf(outfile, " distance %.4f \n", 01183 (get_cue_density() >= 1e4) ? 1e-4 : 1.0/get_cue_density() ); 01184 fprintf(outfile, " fog_type 1 \n"); 01185 break; 01186 01187 case NUM_CUE_MODES: 01188 // this should never happen 01189 break; 01190 } 01191 01192 // for depth-cueing, the fog color is the background color 01193 fprintf(outfile, " color rgb<%.3f, %.3f, %.3f> \n", 01194 backColor[0], backColor[1], backColor[2] ); 01195 fprintf(outfile, "} \n"); 01196 } 01197 } 01198 01199 void POV3DisplayDevice::write_trailer(void){ 01200 fprintf(outfile, "// End of POV-Ray 3.x generation \n"); 01201 01202 if (degenerate_cones != 0) { 01203 msgWarn << "Skipped " << degenerate_cones 01204 << " degenerate cones" << sendmsg; 01205 } 01206 if (degenerate_cylinders != 0) { 01207 msgWarn << "Skipped " << degenerate_cylinders 01208 << " degenerate cylinders" << sendmsg; 01209 } 01210 if (degenerate_triangles != 0) { 01211 msgWarn << "Skipped " << degenerate_triangles 01212 << " degenerate triangles" << sendmsg; 01213 } 01214 01215 reset_vars(); // Reset variables before the next rendering. 01216 } 01217 01218 01219 void POV3DisplayDevice::write_materials(void) { 01220 if (old_materialIndex != materialIndex) { 01221 01222 old_materialIndex = materialIndex; 01223 01224 fprintf(outfile, "#default { texture {\n"); 01225 fprintf(outfile, " finish { ambient %.3f diffuse %.3f", 01226 mat_ambient, mat_diffuse); 01227 fprintf(outfile, " phong 0.1 phong_size %.3f specular %.3f }\n", 01228 mat_shininess, mat_specular); 01229 fprintf(outfile, "} }\n"); 01230 } 01231 } 01232 01233 01234 void POV3DisplayDevice::start_clipgroup(void) { 01235 int i, num_clipplanes[3], mode; 01236 float pov_clip_center[3], pov_clip_distance[VMD_MAX_CLIP_PLANE]; 01237 float pov_clip_normal[VMD_MAX_CLIP_PLANE][3]; 01238 01239 write_materials(); 01240 01241 memset(num_clipplanes, 0, 3*sizeof(int)); 01242 for (i = 0; i < VMD_MAX_CLIP_PLANE; i++) { 01243 if (clip_mode[i] != 0) { 01244 // Count the number of clipping planes for each clip mode 01245 num_clipplanes[clip_mode[i]]++; 01246 01247 // Translate the plane center 01248 (transMat.top()).multpoint3d(clip_center[i], pov_clip_center); 01249 01250 // and the normal 01251 (transMat.top()).multnorm3d(clip_normal[i], pov_clip_normal[i]); 01252 vec_negate(pov_clip_normal[i], pov_clip_normal[i]); 01253 01254 // POV-Ray uses the distance from the origin to the plane for its 01255 // representation, instead of the plane center 01256 pov_clip_distance[i] = dot_prod(pov_clip_normal[i], pov_clip_center); 01257 } 01258 } 01259 01260 // Define the clip object for each clip mode 01261 for (mode = 1; mode < 3; mode++) { 01262 if (num_clipplanes[mode] > 0) { 01263 // This flag is used within VMD to determine if clipping information 01264 // should be written to the scene file 01265 clip_on[mode] = 1; 01266 01267 // This flag is used within POV to determine if clipping should be done 01268 // within macros 01269 fprintf(outfile, "#declare VMD_clip_on[%d]=1;\n", mode); 01270 01271 if (num_clipplanes[mode] == 1) { 01272 for (i = 0; i < VMD_MAX_CLIP_PLANE; i++) { 01273 if (clip_mode[i] == mode) { 01274 if (mode == 2) { 01275 // Textured plane for CSG clipping 01276 fprintf(outfile, "#declare VMD_clip[%d] = plane { <%.4f, %.4f, %.4f>, %.4f texture { pigment { rgbt<%.3f, %.3f, %.3f, %.3f> } } }\n", 01277 mode, pov_clip_normal[i][0], pov_clip_normal[i][1], 01278 -pov_clip_normal[i][2], pov_clip_distance[i], 01279 clip_color[i][0], clip_color[i][1], clip_color[i][2], 01280 1 - mat_opacity); 01281 } else { 01282 // Non-textured plane for non-CSG clipping 01283 fprintf(outfile, "#declare VMD_clip[%d] = plane { <%.4f, %.4f, %.4f>, %.4f }\n", 01284 mode, pov_clip_normal[i][0], pov_clip_normal[i][1], 01285 -pov_clip_normal[i][2], pov_clip_distance[i]); 01286 01287 #if defined(POVRAY_BRAIN_DAMAGE_WORKAROUND) 01288 // Non-textured plane for non-CSG clipping, but scaled for use 01289 // when emitting meshes with the scaling hack. 01290 fprintf(outfile, "#declare VMD_scaledclip[%d] = plane { <%.4f, %.4f, %.4f>, %.4f }\n", 01291 mode, pov_clip_normal[i][0], pov_clip_normal[i][1], -pov_clip_normal[i][2], 01292 pov_clip_distance[i] * POVRAY_SCALEHACK); 01293 #endif 01294 } 01295 } 01296 } 01297 } 01298 01299 // Declare the clipping object to be an intersection of planes 01300 else { 01301 fprintf(outfile, "#declare VMD_clip[%d] = intersection {\n", mode); 01302 for (i = 0; i < VMD_MAX_CLIP_PLANE; i++) { 01303 if (clip_mode[i] == mode) { 01304 if (mode == 2) { 01305 // Textured plane for CSG clipping 01306 fprintf(outfile, " plane { <%.4f, %.4f, %.4f>, %.4f texture { pigment { rgbt<%.3f, %.3f, %.3f, %.3f> } } }\n", 01307 pov_clip_normal[i][0], pov_clip_normal[i][1], 01308 -pov_clip_normal[i][2], pov_clip_distance[i], 01309 clip_color[i][0], clip_color[i][1], clip_color[i][2], 01310 1 - mat_opacity); 01311 } else { 01312 // Non-textured plane for non-CSG clipping 01313 fprintf(outfile, " plane { <%.4f, %.4f, %.4f>, %.4f }\n", 01314 pov_clip_normal[i][0], pov_clip_normal[i][1], 01315 -pov_clip_normal[i][2], pov_clip_distance[i]); 01316 } 01317 } 01318 } 01319 fprintf(outfile, "}\n"); 01320 01321 #if defined(POVRAY_BRAIN_DAMAGE_WORKAROUND) 01322 fprintf(outfile, "#declare VMD_scaledclip[%d] = intersection {\n", mode); 01323 for (i = 0; i < VMD_MAX_CLIP_PLANE; i++) { 01324 if (clip_mode[i] == mode) { 01325 if (mode == 2) { 01326 // Textured plane for CSG clipping 01327 fprintf(outfile, " plane { <%.4f, %.4f, %.4f>, %.4f texture { pigment { rgbt<%.3f, %.3f, %.3f, %.3f> } } }\n", 01328 pov_clip_normal[i][0], pov_clip_normal[i][1], 01329 -pov_clip_normal[i][2], pov_clip_distance[i] * POVRAY_SCALEHACK, 01330 clip_color[i][0], clip_color[i][1], clip_color[i][2], 01331 1 - mat_opacity); 01332 } else { 01333 // Non-textured plane for non-CSG clipping 01334 fprintf(outfile, " plane { <%.4f, %.4f, %.4f>, %.4f }\n", 01335 pov_clip_normal[i][0], pov_clip_normal[i][1], 01336 -pov_clip_normal[i][2], pov_clip_distance[i] * POVRAY_SCALEHACK); 01337 } 01338 } 01339 } 01340 fprintf(outfile, "}\n"); 01341 #endif 01342 01343 01344 } 01345 01346 } 01347 } 01348 } 01349 01350 void POV3DisplayDevice::end_clipgroup(void) { 01351 int i; 01352 for (i = 0; i < 3; i++) { 01353 if (clip_on[i]) { 01354 fprintf(outfile, "#declare VMD_clip_on[%d]=0;\n", i); 01355 clip_on[i] = 0; 01356 } 01357 } 01358 } 01359 01360 void POV3DisplayDevice::set_line_width(int new_width) { 01361 // XXX - find out why lineWidth is getting set outside this function! 01362 // if (lineWidth != new_width) { 01363 { 01364 lineWidth = new_width; 01365 fprintf(outfile, "#declare VMD_line_width=%.4f;\n", 01366 ((float)new_width)*DEFAULT_RADIUS); 01367 } 01368 } 01369