00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023 #include <stdlib.h>
00024 #include <stdio.h>
00025 #include <ctype.h>
00026 #include <math.h>
00027 #include <string.h>
00028
00029 #if defined(_AIX)
00030 #include <strings.h>
00031 #endif
00032
00033 #if defined(WIN32) || defined(WIN64)
00034 #define strcasecmp stricmp
00035 #endif
00036
00037 #include "molfile_plugin.h"
00038
00039
00040 #define BUFSZ 1024
00041
00042
00043 typedef struct {
00044 FILE *f;
00045 char *headerbuf;
00046 int isbinary;
00047 int islittleendian;
00048 long dataoffset;
00049
00050
00051 int hastrimesh;
00052 int nvertices;
00053 int ntriangles;
00054
00055
00056 int nsets;
00057 molfile_volumetric_t *vol;
00058 } am_t;
00059
00060
00061 static char *get_next_noncomment_line(char *buf, int bufsz, FILE *f) {
00062 while (1) {
00063 char *res = fgets(buf, bufsz, f);
00064 if (!res || (res[0] != '#' && res[0] != '\n' && res[0] != '\r'))
00065 return res;
00066 }
00067 }
00068
00069 static long find_data_offset(FILE *f) {
00070 char buf[BUFSZ];
00071 while (1) {
00072 char *res = fgets(buf, BUFSZ, f);
00073 if (!res || (res[0] != '#' && res[0] != '\n' && res[0] != '\r')) {
00074 if (!res) {
00075 return -1;
00076 } else if (strstr(res, "# Data section follows")) {
00077 return ftell(f);
00078
00079
00080 }
00081 }
00082 }
00083 }
00084
00085
00086 static int amira_readvar_int(am_t *am, char *varname, int *val) {
00087 char *pos = strstr(am->headerbuf, varname);
00088 if (pos != NULL) {
00089 if (sscanf(am->headerbuf, "%*s %d", val) == 2) {
00090 return 0;
00091 }
00092 printf("amiraplugin) failed to find variable '%s' in header\n", varname);
00093 return -1;
00094 }
00095
00096 return -1;
00097 }
00098
00099
00100 static int amira_readvar_float(am_t *am, char *varname, float *val) {
00101 char *pos = strstr(am->headerbuf, varname);
00102 if (pos != NULL) {
00103 if (sscanf(am->headerbuf, "%*s %f", val) == 2) {
00104 return 0;
00105 }
00106 printf("amiraplugin) failed to find variable '%s' in header\n", varname);
00107 return -1;
00108 }
00109
00110 return -1;
00111 }
00112
00113
00114 static int amira_check_trimesh(am_t *am) {
00115
00116 if ((strstr(am->headerbuf, "Vertices { float[3] Vertices }") != NULL) &&
00117 (strstr(am->headerbuf, "TriangleData { int[7] Triangles }") != NULL)) {
00118 int rc;
00119 rc=amira_readvar_int(am, "nVertices", &am->nvertices);
00120 if (!rc) rc=amira_readvar_int(am, "nVertices", &am->ntriangles);
00121 if (!rc) {
00122 am->hastrimesh = 1;
00123 printf("amiraplugin) Found RGBA triangle mesh: %d verts, %d tris\n",
00124 am->nvertices, am->ntriangles);
00125 return 1;
00126 } else {
00127 printf("amiraplugin) Failed to find vertex/triangle counts for mesh!\n");
00128 }
00129 }
00130 return 0;
00131 }
00132
00133
00134 static void *open_file_read(const char *filepath, const char *filetype,
00135 int *natoms) {
00136 FILE *f=NULL;
00137 am_t *am=NULL;
00138 *natoms = 0;
00139
00140 f = fopen(filepath, "rb");
00141 if (!f) {
00142 printf("amiraplugin) Error opening file.\n");
00143 return NULL;
00144 }
00145
00146
00147 char linebuf[BUFSZ];
00148 fgets(linebuf, BUFSZ, f);
00149 if (strncmp(linebuf, "# AmiraMesh", strlen("# AmiraMesh")) != 0) {
00150 printf("amiraplugin) Bad file header: '%s'\n", linebuf);
00151 return NULL;
00152 }
00153
00154 char endianbuf[BUFSZ];
00155 char versionbuf[BUFSZ];
00156 char commentbuf[BUFSZ];
00157 int parsed=sscanf("# AmiraMesh %s %s %s", endianbuf, versionbuf, commentbuf);
00158 if (parsed < 2) {
00159 printf("amiraplugin) Bad file header: '%s'\n", linebuf);
00160 return NULL;
00161 }
00162
00163 am = new am_t;
00164 memset(am, 0, sizeof(am_t));
00165 am->f = f;
00166 am->hastrimesh = 0;
00167 am->nsets = 0;
00168 am->vol = NULL;
00169
00170 if (strstr(linebuf, "BINARY-LITTLE-ENDIAN") != NULL) {
00171 am->isbinary=1;
00172 am->islittleendian=1;
00173 } else if (strstr(linebuf, "BINARY-BIG-ENDIAN") != NULL) {
00174 am->isbinary=1;
00175 am->islittleendian=1;
00176 } else if (strstr(linebuf, "ASCII") != NULL) {
00177 am->isbinary=0;
00178 am->islittleendian=0;
00179 } else {
00180 printf("amiraplugin) Failed to parse header data format: '%s'\n",
00181 endianbuf);
00182 delete am;
00183 return NULL;
00184 }
00185
00186
00187
00188
00189
00190 am->dataoffset = find_data_offset(am->f);
00191 if (am->dataoffset < 0) {
00192 printf("amiraplugin) Failed to find data offset!\n");
00193 delete am;
00194 return NULL;
00195 }
00196 if (am->dataoffset > 1000000) {
00197 printf("amiraplugin) Header appears to be overly large, aborting read!\n");
00198 delete am;
00199 return NULL;
00200 }
00201
00202 am->headerbuf = (char*) calloc(1, am->dataoffset);
00203 rewind(am->f);
00204 fread(am->headerbuf, am->dataoffset, 1, am->f);
00205
00206
00207
00208 amira_check_trimesh(am);
00209
00210 return am;
00211 }
00212
00213
00214 static void close_file_read(void *v) {
00215 am_t *am = (am_t *)v;
00216
00217 fclose(am->f);
00218 if (am->vol != NULL)
00219 delete [] am->vol;
00220 delete am;
00221 }
00222
00223
00224 static int read_volumetric_metadata(void *v, int *nsets,
00225 molfile_volumetric_t **metadata) {
00226 am_t *am = (am_t *)v;
00227 *nsets = am->nsets;
00228 *metadata = am->vol;
00229
00230 return MOLFILE_SUCCESS;
00231 }
00232
00233
00234 static int read_volumetric_data(void *v, int set, float *datablock,
00235 float *colorblock) {
00236 return MOLFILE_ERROR;
00237
00238 }
00239
00240
00241 static int read_rawgraphics(void *v, int *nelem,
00242 const molfile_graphics_t **data) {
00243 #if 0
00244 int i, k, n;
00245 int nVert, nFaces, nEdges;
00246 float *vertices = NULL, *vertColors = NULL;
00247 char *vertHasColor = NULL;
00248 molfile_graphics_t *graphics = NULL;
00249 int j=0;
00250
00251 char buff[BUFFLEN+1];
00252 FILE *infile = (FILE *)v;
00253
00254
00255 nextNoncommentLine(buff, BUFFLEN, infile);
00256 if (buff[0] != 'O' || buff[1] != 'F' || buff[2] != 'F') {
00257 fprintf(stderr, "offplugin) error: expected \"OFF\" header.\n");
00258 goto error;
00259 }
00260
00261
00262 nextNoncommentLine(buff, BUFFLEN, infile);
00263 if (sscanf (buff, " %d %d %d", &nVert, &nFaces, &nEdges) < 2 ||
00264 nVert <= 0 || nFaces <= 0) {
00265 fprintf(stderr, "offplugin) error: wrong number of elements.\n");
00266 goto error;
00267 }
00268
00269
00270 vertices = (float *) calloc (3 * nVert, sizeof(float));
00271 vertHasColor = (char *) calloc (nVert, sizeof(char));
00272 vertColors = (float *) calloc (3 * nVert, sizeof(float));
00273 for (i = 0; i < nVert; i++) {
00274 nextNoncommentLine(buff, BUFFLEN, infile);
00275 int n = sscanf (buff, " %g %g %g %g %g %g",
00276 &vertices[3*i], &vertices[3*i+1], &vertices[3*i+2],
00277 &vertColors[3*i], &vertColors[3*i+1], &vertColors[3*i+2]);
00278 if (n != 3 && n != 6) {
00279 fprintf(stderr, "offplugin) error: not enough data.\n");
00280 goto error;
00281 }
00282 vertHasColor[i] = (n == 6);
00283 }
00284
00285
00286
00287
00288
00289 graphics = (molfile_graphics_t *) calloc(6*nFaces, sizeof(molfile_graphics_t));
00290 n = 0;
00291 for (i = 0; i < nFaces; i++) {
00292 int idx[4];
00293 float c[3];
00294 nextNoncommentLine(buff, BUFFLEN, infile);
00295
00296 if (sscanf (buff, "%d", &k) != 1 || k < 3) {
00297 fprintf(stderr, "offplugin) error: not enough data.\n");
00298 goto error;
00299 }
00300
00301 if (k > 4) {
00302
00303
00304
00305 fprintf(stderr, "offplugin) error: TODO -- handling polygons with more than 4 vertices.\n");
00306 goto error;
00307 }
00308
00309 if (k == 3) {
00310 j = sscanf (buff, "%d %d %d %d %g %g %g", &k, &idx[0], &idx[1], &idx[2], &c[0], &c[1], &c[2]);
00311 bool hasColor = ((j == 7) || (vertHasColor[idx[0]] && vertHasColor[idx[1]] && vertHasColor[idx[2]]));
00312
00313 graphics[n].type = (hasColor ? MOLFILE_TRICOLOR : MOLFILE_TRIANGLE);
00314 graphics[n].data[0] = vertices[3*idx[0] ];
00315 graphics[n].data[1] = vertices[3*idx[0]+1];
00316 graphics[n].data[2] = vertices[3*idx[0]+2];
00317 graphics[n].data[3] = vertices[3*idx[1] ];
00318 graphics[n].data[4] = vertices[3*idx[1]+1];
00319 graphics[n].data[5] = vertices[3*idx[1]+2];
00320 graphics[n].data[6] = vertices[3*idx[2] ];
00321 graphics[n].data[7] = vertices[3*idx[2]+1];
00322 graphics[n].data[8] = vertices[3*idx[2]+2];
00323 n++;
00324
00325 if (j == 7) {
00326
00327 graphics[n].type = MOLFILE_NORMS;
00328 calcNormals (graphics[n-1].data, graphics[n].data);
00329 n++;
00330
00331 graphics[n].type = MOLFILE_COLOR;
00332 graphics[n].data[0] = graphics[n].data[3] = graphics[n].data[6] = c[0];
00333 graphics[n].data[1] = graphics[n].data[4] = graphics[n].data[7] = c[1];
00334 graphics[n].data[2] = graphics[n].data[5] = graphics[n].data[8] = c[2];
00335 n++;
00336 } else if (hasColor) {
00337
00338 graphics[n].type = MOLFILE_NORMS;
00339 calcNormals (graphics[n-1].data, graphics[n].data);
00340 n++;
00341
00342 graphics[n].type = MOLFILE_COLOR;
00343 graphics[n].data[0] = vertColors[3*idx[0] ];
00344 graphics[n].data[1] = vertColors[3*idx[0]+1];
00345 graphics[n].data[2] = vertColors[3*idx[0]+2];
00346 graphics[n].data[3] = vertColors[3*idx[1] ];
00347 graphics[n].data[4] = vertColors[3*idx[1]+1];
00348 graphics[n].data[5] = vertColors[3*idx[1]+2];
00349 graphics[n].data[6] = vertColors[3*idx[2] ];
00350 graphics[n].data[7] = vertColors[3*idx[2]+1];
00351 graphics[n].data[8] = vertColors[3*idx[2]+2];
00352 n++;
00353 }
00354 } else if (k == 4) {
00355 j = sscanf (buff, "%d %d %d %d %d %g %g %g", &k, &idx[0], &idx[1], &idx[2], &idx[3], &c[0], &c[1], &c[2]);
00356 bool hasColor = ((j == 8) || (vertHasColor[idx[0]] && vertHasColor[idx[1]] && vertHasColor[idx[2]] && vertHasColor[idx[3]]));
00357
00358
00359 graphics[n].type = (hasColor ? MOLFILE_TRICOLOR : MOLFILE_TRIANGLE);
00360 graphics[n].data[0] = vertices[3*idx[0] ];
00361 graphics[n].data[1] = vertices[3*idx[0]+1];
00362 graphics[n].data[2] = vertices[3*idx[0]+2];
00363 graphics[n].data[3] = vertices[3*idx[1] ];
00364 graphics[n].data[4] = vertices[3*idx[1]+1];
00365 graphics[n].data[5] = vertices[3*idx[1]+2];
00366 graphics[n].data[6] = vertices[3*idx[2] ];
00367 graphics[n].data[7] = vertices[3*idx[2]+1];
00368 graphics[n].data[8] = vertices[3*idx[2]+2];
00369 n++;
00370
00371 if (j == 8) {
00372 graphics[n].type = MOLFILE_NORMS;
00373 calcNormals (graphics[n-1].data, graphics[n].data);
00374 n++;
00375
00376 graphics[n].type = MOLFILE_COLOR;
00377 graphics[n].data[0] = graphics[n].data[3] = graphics[n].data[6] = c[0];
00378 graphics[n].data[1] = graphics[n].data[4] = graphics[n].data[7] = c[1];
00379 graphics[n].data[2] = graphics[n].data[5] = graphics[n].data[8] = c[2];
00380 n++;
00381 } else if (hasColor) {
00382 graphics[n].type = MOLFILE_NORMS;
00383 calcNormals (graphics[n-1].data, graphics[n].data);
00384 n++;
00385
00386 graphics[n].type = MOLFILE_COLOR;
00387 graphics[n].data[0] = vertColors[3*idx[0]];
00388 graphics[n].data[1] = vertColors[3*idx[0]+1];
00389 graphics[n].data[2] = vertColors[3*idx[0]+2];
00390 graphics[n].data[3] = vertColors[3*idx[1]];
00391 graphics[n].data[4] = vertColors[3*idx[1]+1];
00392 graphics[n].data[5] = vertColors[3*idx[1]+2];
00393 graphics[n].data[6] = vertColors[3*idx[2]];
00394 graphics[n].data[7] = vertColors[3*idx[2]+1];
00395 graphics[n].data[8] = vertColors[3*idx[2]+2];
00396 n++;
00397 }
00398
00399 graphics[n].type = (hasColor ? MOLFILE_TRICOLOR : MOLFILE_TRIANGLE);
00400 graphics[n].data[0] = vertices[3*idx[2]];
00401 graphics[n].data[1] = vertices[3*idx[2]+1];
00402 graphics[n].data[2] = vertices[3*idx[2]+2];
00403 graphics[n].data[3] = vertices[3*idx[3]];
00404 graphics[n].data[4] = vertices[3*idx[3]+1];
00405 graphics[n].data[5] = vertices[3*idx[3]+2];
00406 graphics[n].data[6] = vertices[3*idx[0]];
00407 graphics[n].data[7] = vertices[3*idx[0]+1];
00408 graphics[n].data[8] = vertices[3*idx[0]+2];
00409 n++;
00410
00411 if (j == 8) {
00412 graphics[n].type = MOLFILE_NORMS;
00413 calcNormals (graphics[n-1].data, graphics[n].data);
00414 n++;
00415
00416 graphics[n].type = MOLFILE_COLOR;
00417 graphics[n].data[0] = graphics[n].data[3] = graphics[n].data[6] = c[0];
00418 graphics[n].data[1] = graphics[n].data[4] = graphics[n].data[7] = c[1];
00419 graphics[n].data[2] = graphics[n].data[5] = graphics[n].data[8] = c[2];
00420 n++;
00421 } else if (hasColor) {
00422 graphics[n].type = MOLFILE_NORMS;
00423 calcNormals (graphics[n-1].data, graphics[n].data);
00424 n++;
00425
00426 graphics[n].type = MOLFILE_COLOR;
00427 graphics[n].data[0] = vertColors[3*idx[2]];
00428 graphics[n].data[1] = vertColors[3*idx[2]+1];
00429 graphics[n].data[2] = vertColors[3*idx[2]+2];
00430 graphics[n].data[3] = vertColors[3*idx[3]];
00431 graphics[n].data[4] = vertColors[3*idx[3]+1];
00432 graphics[n].data[5] = vertColors[3*idx[3]+2];
00433 graphics[n].data[6] = vertColors[3*idx[0]];
00434 graphics[n].data[7] = vertColors[3*idx[0]+1];
00435 graphics[n].data[8] = vertColors[3*idx[0]+2];
00436 n++;
00437 }
00438 }
00439 }
00440
00441 *nelem = n;
00442 *data = (molfile_graphics_t *) realloc(graphics, n*sizeof(molfile_graphics_t));
00443 return MOLFILE_SUCCESS;
00444
00445
00446 error:
00447 free (graphics);
00448 free (vertices);
00449 #endif
00450
00451 printf("amiraplugin) read rawgraphics not implemented yet...\n");
00452 return MOLFILE_ERROR;
00453 }
00454
00455
00456
00457
00458
00459
00460
00461 static molfile_plugin_t plugin;
00462
00463 VMDPLUGIN_API int VMDPLUGIN_init(void) {
00464 memset(&plugin, 0, sizeof(molfile_plugin_t));
00465 plugin.abiversion = vmdplugin_ABIVERSION;
00466 plugin.type = MOLFILE_PLUGIN_TYPE;
00467 plugin.name = "am";
00468 plugin.prettyname = "Amira File Format (.am)";
00469 plugin.author = "John Stone";
00470 plugin.majorv = 0;
00471 plugin.minorv = 1;
00472 plugin.is_reentrant = VMDPLUGIN_THREADSAFE;
00473 plugin.filename_extension = "am";
00474 plugin.open_file_read = open_file_read;
00475 plugin.read_volumetric_metadata = read_volumetric_metadata;
00476 plugin.read_volumetric_data = read_volumetric_data;
00477 plugin.read_rawgraphics = read_rawgraphics;
00478 plugin.close_file_read = close_file_read;
00479 return VMDPLUGIN_SUCCESS;
00480 }
00481
00482 VMDPLUGIN_API int VMDPLUGIN_register(void *v, vmdplugin_register_cb cb) {
00483 (*cb)(v, (vmdplugin_t *)&plugin);
00484 return VMDPLUGIN_SUCCESS;
00485 }
00486
00487 VMDPLUGIN_API int VMDPLUGIN_fini(void) { return VMDPLUGIN_SUCCESS; }
00488
00489
00490