00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00032 #include <stdio.h>
00033 #include <string.h>
00034 #include <math.h>
00035 #include <time.h>
00036 #include "WavefrontDisplayDevice.h"
00037 #include "Matrix4.h"
00038 #include "DispCmds.h"
00039 #include "Inform.h"
00040 #include "utilities.h"
00041 #include "config.h"
00042
00043 #define DASH_LENGTH 0.02f
00044
00045 #define VMDGENMTLFILE 1
00046
00047 static int replacefileextension(char * s,
00048 const char * oldextension,
00049 const char * newextension) {
00050 int sz, extsz;
00051 sz = strlen(s);
00052 extsz = strlen(oldextension);
00053
00054 if (strlen(newextension) != strlen(oldextension))
00055 return -1;
00056
00057 if (extsz > sz)
00058 return -1;
00059
00060 if (strupncmp(s + (sz - extsz), oldextension, extsz)) {
00061 return -1;
00062 }
00063
00064 strcpy(s + (sz - extsz), newextension);
00065
00066 return 0;
00067 }
00068
00069 static char * stripleadingfilepath(const char *fullpath) {
00070 int i, j;
00071 char *s = NULL;
00072 int len=strlen(fullpath);
00073 s = (char *) calloc(1, len+1);
00074
00075
00076
00077 for (i=0,j=0; i<len; i++) {
00078 if (fullpath[i] == '/' || fullpath[i] == '\\')
00079 j=i;
00080 }
00081
00082
00083 if (j != 0)
00084 strcpy(s, fullpath+j+1);
00085 else
00086 strcpy(s, fullpath);
00087
00088 return s;
00089 }
00090
00091
00092
00093 WavefrontDisplayDevice::WavefrontDisplayDevice(void)
00094 : FileRenderer("Wavefront", "Wavefront (OBJ and MTL)", "vmdscene.obj", "true") { }
00095
00096
00097 WavefrontDisplayDevice::~WavefrontDisplayDevice(void) { }
00098
00099
00100 void WavefrontDisplayDevice::beginrepgeomgroup(const char *s) {
00101 fprintf(outfile, "g %s\n", s);
00102 }
00103
00104
00105 void WavefrontDisplayDevice::comment(const char *s) {
00106 fprintf(outfile, "# %s\n", s);
00107 }
00108
00109
00110 void WavefrontDisplayDevice::point(float * spdata) {
00111 float vec[3];
00112
00113 (transMat.top()).multpoint3d(spdata, vec);
00114
00115
00116 fprintf(outfile, "v %5f %5f %5f\n", vec[0], vec[1], -vec[2]);
00117 fprintf(outfile, "p -1\n");
00118 }
00119
00120
00121 void WavefrontDisplayDevice::line(float *a, float*b) {
00122 int i, j, test;
00123 float dirvec[3], unitdirvec[3];
00124 float from[3], to[3], tmp1[3], tmp2[3];
00125 float len;
00126
00127 if (lineStyle == ::SOLIDLINE) {
00128
00129 (transMat.top()).multpoint3d(a, from);
00130 (transMat.top()).multpoint3d(b, to);
00131
00132
00133 fprintf(outfile, "v %5f %5f %5f\n", from[0], from[1], -from[2]);
00134 fprintf(outfile, "v %5f %5f %5f\n", to[0], to[1], -to[2]);
00135 fprintf(outfile, "l -1 -2\n");
00136 } else if (lineStyle == ::DASHEDLINE) {
00137
00138 (transMat.top()).multpoint3d(a, tmp1);
00139 (transMat.top()).multpoint3d(b, tmp2);
00140
00141
00142 for(i=0; i<3; i++) {
00143 dirvec[i] = tmp2[i] - tmp1[i];
00144 }
00145 len = sqrtf(dirvec[0]*dirvec[0] + dirvec[1]*dirvec[1] + dirvec[2]*dirvec[2])
00146 ;
00147 for(i=0;i<3;i++) {
00148 unitdirvec[i] = dirvec[i] / sqrtf(len);
00149 }
00150
00151 test = 1;
00152 i = 0;
00153 while(test == 1) {
00154 for(j=0;j<3;j++) {
00155 from[j] = (float) (tmp1[j] + (2*i )*DASH_LENGTH*unitdirvec[j]);
00156 to[j] = (float) (tmp1[j] + (2*i + 1)*DASH_LENGTH*unitdirvec[j]);
00157 }
00158
00159 if (fabsf(tmp1[0] - to[0]) >= fabsf(dirvec[0])) {
00160 for(j=0;j<3;j++)
00161 to[j] = tmp2[j];
00162 test = 0;
00163 }
00164
00165
00166 fprintf(outfile, "v %5f %5f %5f\n", from[0], from[1], -from[2]);
00167 fprintf(outfile, "v %5f %5f %5f\n", to[0], to[1], -to[2]);
00168 fprintf(outfile, "l -1 -2\n");
00169 i++;
00170 }
00171 } else {
00172 msgErr << "WavefrontDisplayDevice: Unknown line style "
00173 << lineStyle << sendmsg;
00174 }
00175 }
00176
00177
00178
00179
00180 void WavefrontDisplayDevice::triangle(const float *v1, const float *v2, const float *v3,
00181 const float *n1, const float *n2, const float *n3) {
00182 float a[3], b[3], c[3];
00183 float norm1[3], norm2[3], norm3[3];
00184
00185
00186 (transMat.top()).multpoint3d(v1, a);
00187 (transMat.top()).multpoint3d(v2, b);
00188 (transMat.top()).multpoint3d(v3, c);
00189
00190
00191 (transMat.top()).multnorm3d(n1, norm1);
00192 (transMat.top()).multnorm3d(n2, norm2);
00193 (transMat.top()).multnorm3d(n3, norm3);
00194
00195 #ifdef VMDGENMTLFILE
00196
00197 write_cindexmaterial(colorIndex, materialIndex);
00198 #endif
00199
00200
00201 fprintf(outfile,"v %f %f %f\n", a[0], a[1], a[2]);
00202 fprintf(outfile,"v %f %f %f\n", b[0], b[1], b[2]);
00203 fprintf(outfile,"v %f %f %f\n", c[0], c[1], c[2]);
00204 fprintf(outfile,"vn %.4f %.4f %.4f\n", norm1[0], norm1[1], norm1[2]);
00205 fprintf(outfile,"vn %.4f %.4f %.4f\n", norm2[0], norm2[1], norm2[2]);
00206 fprintf(outfile,"vn %.4f %.4f %.4f\n", norm3[0], norm3[1], norm3[2]);
00207 fprintf(outfile,"f -3//-3 -2//-2 -1//-1\n");
00208 }
00209
00210
00211
00212
00213 void WavefrontDisplayDevice::trimesh_c4n3v3(int numverts, float * cnv,
00214 int numfacets, int * facets) {
00215 int i;
00216 float vec1[3];
00217 float norm1[3];
00218 const float onethird = (1.0f / 3.0f);
00219
00220
00221 for (i=0; i<numverts; i++) {
00222 int idx = i*10;
00223
00224 (transMat.top()).multpoint3d(cnv + idx + 7, vec1);
00225 fprintf(outfile, "v %f %f %f\n", vec1[0], vec1[1], vec1[2]);
00226
00227 (transMat.top()).multnorm3d(cnv + idx + 4, norm1);
00228 fprintf(outfile, "vn %.4f %.4f %.4f\n", norm1[0], norm1[1], norm1[2]);
00229 }
00230
00231
00232 for (i=0; i<numfacets*3; i+=3) {
00233 int v0 = facets[i ];
00234 int v1 = facets[i + 1];
00235 int v2 = facets[i + 2];
00236
00237 #ifdef VMDGENMTLFILE
00238
00239
00240
00241 const float *c1 = cnv + v0 * 10;
00242 const float *c2 = cnv + v1 * 10;
00243 const float *c3 = cnv + v2 * 10;
00244 float r, g, b;
00245 r = (c1[0] + c2[0] + c3[0]) * onethird;
00246 g = (c1[1] + c2[1] + c3[1]) * onethird;
00247 b = (c1[2] + c2[2] + c3[2]) * onethird;
00248
00249 int cindex = nearest_index(r, g, b);
00250 write_cindexmaterial(cindex, materialIndex);
00251 #endif
00252
00253
00254 v0 -= numverts;
00255 v1 -= numverts;
00256 v2 -= numverts;
00257 fprintf(outfile, "f %d//%d %d//%d %d//%d\n", v0, v0, v1, v1, v2, v2);
00258 }
00259 }
00260
00261
00262
00263
00264 void WavefrontDisplayDevice::trimesh_c4u_n3b_v3f(unsigned char *c,
00265 signed char *n,
00266 float *v, int numfacets) {
00267 int i;
00268 float vec1[3];
00269 float norm1[3];
00270 int numverts = 3*numfacets;
00271
00272 const float onethird = (1.0f / 3.0f);
00273 const float ci2f = 1.0f / 255.0f;
00274 const float cn2f = 1.0f / 127.5f;
00275
00276
00277 for (i=0; i<numverts; i++) {
00278 float ntmp[3];
00279 int idx = i * 3;
00280
00281 (transMat.top()).multpoint3d(v + idx, vec1);
00282 fprintf(outfile, "v %f %f %f\n", vec1[0], vec1[1], vec1[2]);
00283
00284
00285
00286 ntmp[0] = n[idx ] * cn2f + ci2f;
00287 ntmp[1] = n[idx+1] * cn2f + ci2f;
00288 ntmp[2] = n[idx+2] * cn2f + ci2f;
00289 (transMat.top()).multnorm3d(ntmp, norm1);
00290 fprintf(outfile, "vn %.3f %.3f %.3f\n", norm1[0], norm1[1], norm1[2]);
00291 }
00292
00293
00294 for (i=0; i<numfacets*3; i+=3) {
00295 int idx;
00296
00297 int v0 = i;
00298 int v1 = i+1;
00299 int v2 = i+2;
00300
00301 #ifdef VMDGENMTLFILE
00302
00303
00304
00305
00306
00307
00308 float c0[3], c1[3], c2[3];
00309 idx = v0 * 4;
00310 c0[0] = c[idx ] * ci2f;
00311 c0[1] = c[idx + 1] * ci2f;
00312 c0[2] = c[idx + 2] * ci2f;
00313
00314 idx = v1 * 4;
00315 c1[0] = c[idx ] * ci2f;
00316 c1[1] = c[idx + 1] * ci2f;
00317 c1[2] = c[idx + 2] * ci2f;
00318
00319 idx = v2 * 4;
00320 c2[0] = c[idx ] * ci2f;
00321 c2[1] = c[idx + 1] * ci2f;
00322 c2[2] = c[idx + 2] * ci2f;
00323
00324 float r, g, b;
00325 r = (c0[0] + c1[0] + c2[0]) * onethird;
00326 g = (c0[1] + c1[1] + c2[1]) * onethird;
00327 b = (c0[2] + c1[2] + c2[2]) * onethird;
00328
00329 int cindex = nearest_index(r, g, b);
00330 write_cindexmaterial(cindex, materialIndex);
00331 #endif
00332
00333
00334 v0 -= numverts;
00335 v1 -= numverts;
00336 v2 -= numverts;
00337 fprintf(outfile, "f %d//%d %d//%d %d//%d\n", v0, v0, v1, v1, v2, v2);
00338 }
00339 }
00340
00341
00342 void WavefrontDisplayDevice::tristrip(int numverts, const float * cnv,
00343 int numstrips, const int *vertsperstrip,
00344 const int *facets) {
00345 int i, strip, t, v = 0;
00346 int stripaddr[2][3] = { {0, 1, 2}, {1, 0, 2} };
00347 float vec1[3];
00348 float norm1[3];
00349 const float onethird = (1.0f / 3.0f);
00350
00351
00352 for (i=0; i<numverts; i++) {
00353 int idx = i*10;
00354
00355 (transMat.top()).multpoint3d(cnv + idx + 7, vec1);
00356 fprintf(outfile, "v %f %f %f\n", vec1[0], vec1[1], vec1[2]);
00357
00358 (transMat.top()).multnorm3d(cnv + idx + 4, norm1);
00359 fprintf(outfile, "vn %f %f %f\n", norm1[0], norm1[1], norm1[2]);
00360 }
00361
00362
00363
00364
00365
00366 for (strip=0; strip < numstrips; strip++) {
00367
00368 for (t = 0; t < (vertsperstrip[strip] - 2); t++) {
00369
00370 int v0 = facets[v + (stripaddr[t & 0x01][0])];
00371 int v1 = facets[v + (stripaddr[t & 0x01][1])];
00372 int v2 = facets[v + (stripaddr[t & 0x01][2])];
00373
00374 #ifdef VMDGENMTLFILE
00375
00376
00377
00378 const float *c1 = cnv + v0 * 10;
00379 const float *c2 = cnv + v1 * 10;
00380 const float *c3 = cnv + v2 * 10;
00381 float r, g, b;
00382 r = (c1[0] + c2[0] + c3[0]) * onethird;
00383 g = (c1[1] + c2[1] + c3[1]) * onethird;
00384 b = (c1[2] + c2[2] + c3[2]) * onethird;
00385
00386 int cindex = nearest_index(r, g, b);
00387 write_cindexmaterial(cindex, materialIndex);
00388 #endif
00389
00390
00391 v0 -= numverts;
00392 v1 -= numverts;
00393 v2 -= numverts;
00394 fprintf(outfile, "f %d//%d %d//%d %d//%d\n", v0, v0, v1, v1, v2, v2);
00395 v++;
00396 }
00397 v+=2;
00398 }
00399 }
00400
00401
00402 int WavefrontDisplayDevice::open_file(const char *filename) {
00403 if (isOpened) {
00404 close_file();
00405 }
00406 if ((outfile = fopen(filename, "w")) == NULL) {
00407 msgErr << "Could not open file " << filename
00408 << " in current directory for writing!" << sendmsg;
00409 return FALSE;
00410 }
00411 my_filename = stringdup(filename);
00412
00413 #ifdef VMDGENMTLFILE
00414 mtlfilename = stringdup(filename);
00415 if (replacefileextension(mtlfilename, ".obj", ".mtl")) {
00416 msgErr << "Could not generate material filename" << sendmsg;
00417 return FALSE;
00418 }
00419 if ((mtlfile = fopen(mtlfilename, "w")) == NULL) {
00420 msgErr << "Could not open file " << mtlfilename
00421 << " in current directory for writing!" << sendmsg;
00422 return FALSE;
00423 }
00424 #endif
00425
00426 isOpened = TRUE;
00427 reset_state();
00428 oldColorIndex = -1;
00429 oldMaterialIndex = -1;
00430 oldMaterialState = -1;
00431 return TRUE;
00432 }
00433
00434 void WavefrontDisplayDevice::close_file(void) {
00435 if (outfile) {
00436 fclose(outfile);
00437 outfile = NULL;
00438 }
00439 delete [] my_filename;
00440 my_filename = NULL;
00441
00442 #ifdef VMDGENMTLFILE
00443 if (mtlfile) {
00444 fclose(mtlfile);
00445 mtlfile = NULL;
00446 }
00447 delete [] mtlfilename;
00448 mtlfilename = NULL;
00449 #endif
00450
00451 isOpened = FALSE;
00452 }
00453
00454 void WavefrontDisplayDevice::write_header(void) {
00455 fprintf(outfile, "# Wavefront OBJ file export by VMD\n");
00456 fprintf(outfile, "# \n");
00457 fprintf(outfile, "# Molecular graphics exported from VMD %s\n", VMDVERSION);
00458 fprintf(outfile, "# http://www.ks.uiuc.edu/Research/vmd/\n");
00459 fprintf(outfile, "# \n");
00460
00461 #ifdef VMDGENMTLFILE
00462 fprintf(mtlfile, "# Wavefront OBJ MTL file export by VMD\n");
00463 fprintf(mtlfile, "# \n");
00464 fprintf(mtlfile, "# Molecular graphics exported from VMD %s\n", VMDVERSION);
00465 fprintf(mtlfile, "# http://www.ks.uiuc.edu/Research/vmd/\n");
00466 fprintf(mtlfile, "# \n");
00467
00468 if (mtlfilename) {
00469 char *shortmtlfilename = NULL;
00470 shortmtlfilename = stripleadingfilepath(mtlfilename);
00471 fprintf(outfile, "# Load Material Library paired with this scene:\n");
00472 fprintf(outfile, "mtllib %s\n", shortmtlfilename);
00473 free(shortmtlfilename);
00474 }
00475
00476 write_material_block();
00477 #endif
00478 }
00479
00480 void WavefrontDisplayDevice::write_material_block(void) {
00481 #ifdef VMDGENMTLFILE
00482 int n;
00483
00484
00485 for (n=BEGREGCLRS; n < (BEGREGCLRS + REGCLRS + MAPCLRS); n++) {
00486 float rgb[3];
00487 fprintf(mtlfile, "newmtl vmd_mat_cindex_%d\n", n);
00488 vec_scale(rgb, 0.0f, matData[n]);
00489 fprintf(mtlfile, "Ka %.2f %.2f %.2f\n", rgb[0], rgb[1], rgb[2]);
00490 vec_scale(rgb, 0.65f, matData[n]);
00491 fprintf(mtlfile, "Kd %.2f %.2f %.2f\n", rgb[0], rgb[1], rgb[2]);
00492 vec_scale(rgb, 0.50f, matData[n]);
00493 fprintf(mtlfile, "Ks %.2f %.2f %.2f\n", rgb[0], rgb[1], rgb[2]);
00494 vec_scale(rgb, 0.0f, matData[n]);
00495 fprintf(mtlfile, "Tf %.2f %.2f %.2f\n", rgb[0], rgb[1], rgb[2]);
00496 fprintf(mtlfile, "d 1.0\n");
00497 fprintf(mtlfile, "Ns 40.0\n");
00498 fprintf(mtlfile, "illum_4\n");
00499 fprintf(mtlfile, "\n");
00500 }
00501
00502
00503 for (n=BEGREGCLRS; n < (BEGREGCLRS + REGCLRS + MAPCLRS); n++) {
00504 float rgb[3];
00505 fprintf(mtlfile, "newmtl vmd_nomat_cindex_%d\n", n);
00506 vec_scale(rgb, 0.0f, matData[n]);
00507 fprintf(mtlfile, "Ka %.2f %.2f %.2f\n", rgb[0], rgb[1], rgb[2]);
00508 vec_scale(rgb, 0.65f, matData[n]);
00509 fprintf(mtlfile, "Kd %.2f %.2f %.2f\n", rgb[0], rgb[1], rgb[2]);
00510 fprintf(mtlfile, "illum_0\n");
00511 fprintf(mtlfile, "\n");
00512 }
00513 #endif
00514 }
00515
00516 void WavefrontDisplayDevice::write_cindexmaterial(int cindex, int material) {
00517 #ifdef VMDGENMTLFILE
00518 if ((oldColorIndex != cindex) ||
00519 (oldMaterialIndex != material) ||
00520 (oldMaterialState != materials_on)) {
00521 if (materials_on) {
00522 fprintf(outfile, "usemtl vmd_mat_cindex_%d\n", cindex);
00523 } else {
00524 fprintf(outfile, "usemtl vmd_nomat_cindex_%d\n", cindex);
00525 }
00526 }
00527 #endif
00528 oldMaterialIndex = material;
00529 oldColorIndex = cindex;
00530 oldMaterialState = materials_on;
00531 }
00532
00533 void WavefrontDisplayDevice::write_colormaterial(float *rgb, int material) {
00534 #ifdef VMDGENMTLFILE
00535 int cindex = nearest_index(rgb[0], rgb[1], rgb[2]);
00536 write_cindexmaterial(cindex, material);
00537 #endif
00538 }
00539
00540 void WavefrontDisplayDevice::write_trailer (void) {
00541 msgWarn << "Materials are not exported to Wavefront files.\n";
00542 }
00543