1 /* MACHINE GENERATED FILE, DO NOT EDIT! */
2 
3 #define VMDPLUGIN molfile_offplugin
4 #define STATIC_PLUGIN 1
5 
6 /*
7  *  Object File Format (.off)
8  *
9  *  Represent surfaces composed of polygons. It is documented there:
10  *  http://people.sc.fsu.edu/~jburkardt/data/off/off.html
11  *  http://shape.cs.princeton.edu/benchmark/documentation/off_format.html
12  *
13  *  Contributed by Francois-Xavier Coudert (fxcoudert@gmail.com)
14  *
15  */
16 
17 #include <stdlib.h>
18 #include <stdio.h>
19 #include <ctype.h>
20 #include <math.h>
21 #include <string.h>
22 
23 #if defined(_AIX)
24 #include <strings.h>
25 #endif
26 
27 #if defined(WIN32) || defined(WIN64)
28 #define strcasecmp stricmp
29 #endif
30 
31 #include "molfile_plugin.h"
32 
33 // internal buffer size used in read_rawgraphics()
34 #define BUFFLEN 1024
35 
open_file_read(const char * filepath,const char * filetype,int * natoms)36 static void *open_file_read(const char *filepath, const char *filetype,
37                             int *natoms) {
38   FILE *f;
39 
40   f = fopen(filepath, "rb");
41   if (!f) {
42     fprintf(stderr, "offplugin) Error opening file.\n");
43     return NULL;
44   }
45   *natoms = 0;
46   return f;
47 }
48 
49 
nextNoncommentLine(char * buff,int bufflen,FILE * f)50 static char *nextNoncommentLine(char *buff, int bufflen, FILE *f) {
51   while (1) {
52     char *res = fgets(buff, bufflen, f);
53     if (!res || (res[0] != '#' && res[0] != '\n' && res[0] != '\r'))
54       return res;
55   };
56 }
57 
58 
calcNormals(float vert[9],float norm[9])59 static void calcNormals (float vert[9], float norm[9]) {
60   float x1 = vert[3] - vert[0];
61   float y1 = vert[4] - vert[1];
62   float z1 = vert[5] - vert[2];
63   float x2 = vert[6] - vert[0];
64   float y2 = vert[7] - vert[1];
65   float z2 = vert[8] - vert[2];
66   float nx = y1 * z2 - z1 * y2;
67   float ny = z1 * x2 - x1 * z2;
68   float nz = x1 * y2 - y1 * x2;
69   float n = 1 / sqrtf(nx*nx+ny*ny+nz*nz);
70   norm[0] = norm[3] = norm[6] = n * nx;
71   norm[1] = norm[4] = norm[7] = n * ny;
72   norm[2] = norm[5] = norm[8] = n * nz;
73 }
74 
75 
read_rawgraphics(void * v,int * nelem,const molfile_graphics_t ** data)76 static int read_rawgraphics(void *v, int *nelem,
77                             const molfile_graphics_t **data) {
78   int i, k, n;
79   int nVert, nFaces, nEdges;
80   float *vertices = NULL, *vertColors = NULL;
81   char *vertHasColor = NULL;
82   molfile_graphics_t *graphics = NULL;
83   int j=0;
84 
85   char buff[BUFFLEN+1];
86   FILE *infile = (FILE *)v;
87 
88   // First line is the header: "OFF"
89   nextNoncommentLine(buff, BUFFLEN, infile);
90   if (buff[0] != 'O' || buff[1] != 'F' || buff[2] != 'F') {
91     fprintf(stderr, "offplugin) error: expected \"OFF\" header.\n");
92     goto error;
93   }
94 
95   // Second line: numVertices numFaces numEdges
96   nextNoncommentLine(buff, BUFFLEN, infile);
97   if (sscanf (buff, " %d %d %d", &nVert, &nFaces, &nEdges) < 2 ||
98       nVert <= 0 || nFaces <= 0) {
99     fprintf(stderr, "offplugin) error: wrong number of elements.\n");
100     goto error;
101   }
102 
103   // Read vertices
104   vertices = (float *) calloc (3 * nVert, sizeof(float));
105   vertHasColor = (char *) calloc (nVert, sizeof(char));
106   vertColors = (float *) calloc (3 * nVert, sizeof(float));
107   for (i = 0; i < nVert; i++) {
108     nextNoncommentLine(buff, BUFFLEN, infile);
109     int n = sscanf (buff, " %g %g %g %g %g %g",
110                     &vertices[3*i], &vertices[3*i+1], &vertices[3*i+2],
111                     &vertColors[3*i], &vertColors[3*i+1], &vertColors[3*i+2]);
112     if (n != 3 && n != 6) {
113       fprintf(stderr, "offplugin) error: not enough data.\n");
114       goto error;
115     }
116     vertHasColor[i] = (n == 6);
117   }
118 
119   // Read faces
120   // We alloc 6 times the memory because:
121   //   -- a quadrangle will be transformed into two triangles.
122   //   -- each triangle may have color, and then also its norm will be specified
123   graphics = (molfile_graphics_t *) calloc(6*nFaces, sizeof(molfile_graphics_t));
124   n = 0;
125   for (i = 0; i < nFaces; i++) {
126     int idx[4];
127     float c[3];
128     nextNoncommentLine(buff, BUFFLEN, infile);
129 
130     if (sscanf (buff, "%d", &k) != 1 || k < 3) {
131       fprintf(stderr, "offplugin) error: not enough data.\n");
132       goto error;
133     }
134 
135     if (k > 4) {
136       // TODO -- handle polygon decomposition into triangles
137       // Follow the algorithm there:
138       // http://www.flipcode.com/archives/Efficient_Polygon_Triangulation.shtml
139       fprintf(stderr, "offplugin) error: TODO -- handling polygons with more than 4 vertices.\n");
140       goto error;
141     }
142 
143     if (k == 3) {
144       j = sscanf (buff, "%d %d %d %d %g %g %g", &k, &idx[0], &idx[1], &idx[2], &c[0], &c[1], &c[2]);
145       bool hasColor = ((j == 7) || (vertHasColor[idx[0]] && vertHasColor[idx[1]] && vertHasColor[idx[2]]));
146 
147       graphics[n].type = (hasColor ? MOLFILE_TRICOLOR : MOLFILE_TRIANGLE);
148       graphics[n].data[0] = vertices[3*idx[0]  ];
149       graphics[n].data[1] = vertices[3*idx[0]+1];
150       graphics[n].data[2] = vertices[3*idx[0]+2];
151       graphics[n].data[3] = vertices[3*idx[1]  ];
152       graphics[n].data[4] = vertices[3*idx[1]+1];
153       graphics[n].data[5] = vertices[3*idx[1]+2];
154       graphics[n].data[6] = vertices[3*idx[2]  ];
155       graphics[n].data[7] = vertices[3*idx[2]+1];
156       graphics[n].data[8] = vertices[3*idx[2]+2];
157       n++;
158 
159       if (j == 7) {
160         // The facet has a specific color, use it.
161         graphics[n].type = MOLFILE_NORMS;
162         calcNormals (graphics[n-1].data, graphics[n].data);
163         n++;
164 
165         graphics[n].type = MOLFILE_COLOR;
166         graphics[n].data[0] = graphics[n].data[3] = graphics[n].data[6] = c[0];
167         graphics[n].data[1] = graphics[n].data[4] = graphics[n].data[7] = c[1];
168         graphics[n].data[2] = graphics[n].data[5] = graphics[n].data[8] = c[2];
169         n++;
170       } else if (hasColor) {
171         // All three vertices have a color attribute
172         graphics[n].type = MOLFILE_NORMS;
173         calcNormals (graphics[n-1].data, graphics[n].data);
174         n++;
175 
176         graphics[n].type = MOLFILE_COLOR;
177         graphics[n].data[0] = vertColors[3*idx[0]  ];
178         graphics[n].data[1] = vertColors[3*idx[0]+1];
179         graphics[n].data[2] = vertColors[3*idx[0]+2];
180         graphics[n].data[3] = vertColors[3*idx[1]  ];
181         graphics[n].data[4] = vertColors[3*idx[1]+1];
182         graphics[n].data[5] = vertColors[3*idx[1]+2];
183         graphics[n].data[6] = vertColors[3*idx[2]  ];
184         graphics[n].data[7] = vertColors[3*idx[2]+1];
185         graphics[n].data[8] = vertColors[3*idx[2]+2];
186         n++;
187       }
188     } else if (k == 4) {
189       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]);
190       bool hasColor = ((j == 8) || (vertHasColor[idx[0]] && vertHasColor[idx[1]] && vertHasColor[idx[2]] && vertHasColor[idx[3]]));
191 
192       // Split a quadrangle into two triangles
193       graphics[n].type = (hasColor ? MOLFILE_TRICOLOR : MOLFILE_TRIANGLE);
194       graphics[n].data[0] = vertices[3*idx[0]  ];
195       graphics[n].data[1] = vertices[3*idx[0]+1];
196       graphics[n].data[2] = vertices[3*idx[0]+2];
197       graphics[n].data[3] = vertices[3*idx[1]  ];
198       graphics[n].data[4] = vertices[3*idx[1]+1];
199       graphics[n].data[5] = vertices[3*idx[1]+2];
200       graphics[n].data[6] = vertices[3*idx[2]  ];
201       graphics[n].data[7] = vertices[3*idx[2]+1];
202       graphics[n].data[8] = vertices[3*idx[2]+2];
203       n++;
204 
205       if (j == 8) {
206         graphics[n].type = MOLFILE_NORMS;
207         calcNormals (graphics[n-1].data, graphics[n].data);
208         n++;
209 
210         graphics[n].type = MOLFILE_COLOR;
211         graphics[n].data[0] = graphics[n].data[3] = graphics[n].data[6] = c[0];
212         graphics[n].data[1] = graphics[n].data[4] = graphics[n].data[7] = c[1];
213         graphics[n].data[2] = graphics[n].data[5] = graphics[n].data[8] = c[2];
214         n++;
215       } else if (hasColor) {
216         graphics[n].type = MOLFILE_NORMS;
217         calcNormals (graphics[n-1].data, graphics[n].data);
218         n++;
219 
220         graphics[n].type = MOLFILE_COLOR;
221         graphics[n].data[0] = vertColors[3*idx[0]];
222         graphics[n].data[1] = vertColors[3*idx[0]+1];
223         graphics[n].data[2] = vertColors[3*idx[0]+2];
224         graphics[n].data[3] = vertColors[3*idx[1]];
225         graphics[n].data[4] = vertColors[3*idx[1]+1];
226         graphics[n].data[5] = vertColors[3*idx[1]+2];
227         graphics[n].data[6] = vertColors[3*idx[2]];
228         graphics[n].data[7] = vertColors[3*idx[2]+1];
229         graphics[n].data[8] = vertColors[3*idx[2]+2];
230         n++;
231       }
232 
233       graphics[n].type = (hasColor ? MOLFILE_TRICOLOR : MOLFILE_TRIANGLE);
234       graphics[n].data[0] = vertices[3*idx[2]];
235       graphics[n].data[1] = vertices[3*idx[2]+1];
236       graphics[n].data[2] = vertices[3*idx[2]+2];
237       graphics[n].data[3] = vertices[3*idx[3]];
238       graphics[n].data[4] = vertices[3*idx[3]+1];
239       graphics[n].data[5] = vertices[3*idx[3]+2];
240       graphics[n].data[6] = vertices[3*idx[0]];
241       graphics[n].data[7] = vertices[3*idx[0]+1];
242       graphics[n].data[8] = vertices[3*idx[0]+2];
243       n++;
244 
245       if (j == 8) {
246         graphics[n].type = MOLFILE_NORMS;
247         calcNormals (graphics[n-1].data, graphics[n].data);
248         n++;
249 
250         graphics[n].type = MOLFILE_COLOR;
251         graphics[n].data[0] = graphics[n].data[3] = graphics[n].data[6] = c[0];
252         graphics[n].data[1] = graphics[n].data[4] = graphics[n].data[7] = c[1];
253         graphics[n].data[2] = graphics[n].data[5] = graphics[n].data[8] = c[2];
254         n++;
255       } else if (hasColor) {
256         graphics[n].type = MOLFILE_NORMS;
257         calcNormals (graphics[n-1].data, graphics[n].data);
258         n++;
259 
260         graphics[n].type = MOLFILE_COLOR;
261         graphics[n].data[0] = vertColors[3*idx[2]];
262         graphics[n].data[1] = vertColors[3*idx[2]+1];
263         graphics[n].data[2] = vertColors[3*idx[2]+2];
264         graphics[n].data[3] = vertColors[3*idx[3]];
265         graphics[n].data[4] = vertColors[3*idx[3]+1];
266         graphics[n].data[5] = vertColors[3*idx[3]+2];
267         graphics[n].data[6] = vertColors[3*idx[0]];
268         graphics[n].data[7] = vertColors[3*idx[0]+1];
269         graphics[n].data[8] = vertColors[3*idx[0]+2];
270         n++;
271       }
272     }
273   }
274 
275   *nelem = n;
276   *data = (molfile_graphics_t *) realloc(graphics, n*sizeof(molfile_graphics_t));
277   return MOLFILE_SUCCESS;
278 
279   // goto jump target for disaster handling: free memory and bail out
280   error:
281     free (graphics);
282     free (vertices);
283     return MOLFILE_ERROR;
284 }
285 
286 
close_file_read(void * v)287 static void close_file_read(void *v) {
288   fclose((FILE *)v);
289 }
290 
291 
292 /*
293  * Initialization stuff here
294  */
295 static molfile_plugin_t plugin;
296 
VMDPLUGIN_init(void)297 VMDPLUGIN_API int VMDPLUGIN_init(void) {
298   memset(&plugin, 0, sizeof(molfile_plugin_t));
299   plugin.abiversion = vmdplugin_ABIVERSION;
300   plugin.type = MOLFILE_PLUGIN_TYPE;
301   plugin.name = "off";
302   plugin.prettyname = "Object File Format (OFF)";
303   plugin.author = "Francois-Xavier Coudert";
304   plugin.majorv = 0;
305   plugin.minorv = 4;
306   plugin.is_reentrant = VMDPLUGIN_THREADSAFE;
307   plugin.filename_extension = "off";
308   plugin.open_file_read = open_file_read;
309   plugin.read_rawgraphics = read_rawgraphics;
310   plugin.close_file_read = close_file_read;
311   return VMDPLUGIN_SUCCESS;
312 }
313 
VMDPLUGIN_register(void * v,vmdplugin_register_cb cb)314 VMDPLUGIN_API int VMDPLUGIN_register(void *v, vmdplugin_register_cb cb) {
315   (*cb)(v, (vmdplugin_t *)&plugin);
316   return VMDPLUGIN_SUCCESS;
317 }
318 
VMDPLUGIN_fini(void)319 VMDPLUGIN_API int VMDPLUGIN_fini(void) { return VMDPLUGIN_SUCCESS; }
320 
321