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