1 |
|
|
/* |
2 |
|
|
Teem: Tools to process and visualize scientific data and images . |
3 |
|
|
Copyright (C) 2013, 2012, 2011, 2010, 2009 University of Chicago |
4 |
|
|
Copyright (C) 2008, 2007, 2006, 2005 Gordon Kindlmann |
5 |
|
|
Copyright (C) 2004, 2003, 2002, 2001, 2000, 1999, 1998 University of Utah |
6 |
|
|
|
7 |
|
|
This library is free software; you can redistribute it and/or |
8 |
|
|
modify it under the terms of the GNU Lesser General Public License |
9 |
|
|
(LGPL) as published by the Free Software Foundation; either |
10 |
|
|
version 2.1 of the License, or (at your option) any later version. |
11 |
|
|
The terms of redistributing and/or modifying this software also |
12 |
|
|
include exceptions to the LGPL that facilitate static linking. |
13 |
|
|
|
14 |
|
|
This library is distributed in the hope that it will be useful, |
15 |
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of |
16 |
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
17 |
|
|
Lesser General Public License for more details. |
18 |
|
|
|
19 |
|
|
You should have received a copy of the GNU Lesser General Public License |
20 |
|
|
along with this library; if not, write to Free Software Foundation, Inc., |
21 |
|
|
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
22 |
|
|
*/ |
23 |
|
|
|
24 |
|
|
|
25 |
|
|
#include "limn.h" |
26 |
|
|
|
27 |
|
|
int |
28 |
|
|
limnObjectDescribe(FILE *file, const limnObject *obj) { |
29 |
|
|
limnFace *face; unsigned int si, fii; |
30 |
|
|
limnEdge *edge; unsigned int eii; |
31 |
|
|
limnVertex *vert; unsigned int vii; |
32 |
|
|
limnPart *part; unsigned int partIdx; |
33 |
|
|
limnLook *look; |
34 |
|
|
|
35 |
|
|
fprintf(file, "parts: %d\n", obj->partNum); |
36 |
|
|
for (partIdx=0; partIdx<obj->partNum; partIdx++) { |
37 |
|
|
part = obj->part[partIdx]; |
38 |
|
|
fprintf(file, "part %d | verts: %d ========\n", partIdx, part->vertIdxNum); |
39 |
|
|
for (vii=0; vii<part->vertIdxNum; vii++) { |
40 |
|
|
vert = obj->vert + part->vertIdx[vii]; |
41 |
|
|
fprintf(file, "part %d | %d(%d): w=(%g,%g,%g)\n", |
42 |
|
|
partIdx, vii, part->vertIdx[vii], |
43 |
|
|
vert->world[0], vert->world[1], vert->world[2]); |
44 |
|
|
/* vert->view[0], vert->view[1], vert->view[2]); */ |
45 |
|
|
/* vert->screen[0], vert->screen[1], vert->screen[2]); */ |
46 |
|
|
} |
47 |
|
|
fprintf(file, "part %d | edges: %d ========\n", partIdx, part->edgeIdxNum); |
48 |
|
|
for (eii=0; eii<part->edgeIdxNum; eii++) { |
49 |
|
|
edge = obj->edge + part->edgeIdx[eii]; |
50 |
|
|
fprintf(file, "part %d==%d | %d(%d): " |
51 |
|
|
"vert(%d,%d), face(%d,%d)\n", |
52 |
|
|
partIdx, edge->partIdx, eii, part->edgeIdx[eii], |
53 |
|
|
edge->vertIdx[0], edge->vertIdx[1], |
54 |
|
|
edge->faceIdx[0], edge->faceIdx[1]); |
55 |
|
|
} |
56 |
|
|
fprintf(file, "part %d | faces: %d ========\n", partIdx, part->faceIdxNum); |
57 |
|
|
for (fii=0; fii<part->faceIdxNum; fii++) { |
58 |
|
|
face = obj->face + part->faceIdx[fii]; |
59 |
|
|
fprintf(file, "part %d==%d | %d(%d): [", |
60 |
|
|
partIdx, face->partIdx, fii, part->faceIdx[fii]); |
61 |
|
|
for (si=0; si<face->sideNum; si++) { |
62 |
|
|
fprintf(file, "%d", face->vertIdx[si]); |
63 |
|
|
if (si < face->sideNum-1) { |
64 |
|
|
fprintf(file, ","); |
65 |
|
|
} |
66 |
|
|
} |
67 |
|
|
fprintf(file, "]; wn = (%g,%g,%g) |%g|", face->worldNormal[0], |
68 |
|
|
face->worldNormal[1], face->worldNormal[2], |
69 |
|
|
ELL_3V_LEN(face->worldNormal)); |
70 |
|
|
look = obj->look + face->lookIdx; |
71 |
|
|
fprintf(file, "; RGB=(%g,%g,%g)", |
72 |
|
|
look->rgba[0], look->rgba[1], look->rgba[2]); |
73 |
|
|
fprintf(file, "\n"); |
74 |
|
|
} |
75 |
|
|
} |
76 |
|
|
|
77 |
|
|
return 0; |
78 |
|
|
} |
79 |
|
|
|
80 |
|
|
int |
81 |
|
|
limnObjectWriteOFF(FILE *file, const limnObject *obj) { |
82 |
|
|
static const char me[]="limnObjectWriteOFF"; |
83 |
|
|
unsigned int si; |
84 |
|
|
limnVertex *vert; unsigned int vii; |
85 |
|
|
limnFace *face; unsigned int fii; |
86 |
|
|
limnPart *part; unsigned int partIdx; |
87 |
|
|
|
88 |
|
|
if (!( obj && file )) { |
89 |
|
|
biffAddf(LIMN, "%s: got NULL pointer", me); |
90 |
|
|
return 1; |
91 |
|
|
} |
92 |
|
|
fprintf(file, "OFF # created by Teem/limn\n"); |
93 |
|
|
fprintf(file, "%d %d %d\n", obj->vertNum, obj->faceNum, obj->edgeNum); |
94 |
|
|
|
95 |
|
|
/* write vertices */ |
96 |
|
|
for (partIdx=0; partIdx<obj->partNum; partIdx++) { |
97 |
|
|
fprintf(file, "### LIMN BEGIN PART %d\n", partIdx); |
98 |
|
|
part = obj->part[partIdx]; |
99 |
|
|
for (vii=0; vii<part->vertIdxNum; vii++) { |
100 |
|
|
vert = obj->vert + part->vertIdx[vii]; |
101 |
|
|
fprintf(file, "%g %g %g", |
102 |
|
|
vert->world[0]/vert->world[3], |
103 |
|
|
vert->world[1]/vert->world[3], |
104 |
|
|
vert->world[2]/vert->world[3]); |
105 |
|
|
/* verts no longer have a lookIdx |
106 |
|
|
if (vert->lookIdx) { |
107 |
|
|
fprintf(file, " %g %g %g", |
108 |
|
|
obj->look[vert->lookIdx].rgba[0], |
109 |
|
|
obj->look[vert->lookIdx].rgba[1], |
110 |
|
|
obj->look[vert->lookIdx].rgba[2]); |
111 |
|
|
} |
112 |
|
|
*/ |
113 |
|
|
fprintf(file, "\n"); |
114 |
|
|
} |
115 |
|
|
} |
116 |
|
|
|
117 |
|
|
/* write faces */ |
118 |
|
|
for (partIdx=0; partIdx<obj->partNum; partIdx++) { |
119 |
|
|
fprintf(file, "### LIMN BEGIN PART %d\n", partIdx); |
120 |
|
|
part = obj->part[partIdx]; |
121 |
|
|
for (fii=0; fii<part->faceIdxNum; fii++) { |
122 |
|
|
face = obj->face + part->faceIdx[fii]; |
123 |
|
|
fprintf(file, "%d", face->sideNum); |
124 |
|
|
for (si=0; si<face->sideNum; si++) { |
125 |
|
|
fprintf(file, " %d", face->vertIdx[si]); |
126 |
|
|
} |
127 |
|
|
if (face->lookIdx) { |
128 |
|
|
fprintf(file, " %g %g %g", |
129 |
|
|
obj->look[face->lookIdx].rgba[0], |
130 |
|
|
obj->look[face->lookIdx].rgba[1], |
131 |
|
|
obj->look[face->lookIdx].rgba[2]); |
132 |
|
|
} |
133 |
|
|
fprintf(file, "\n"); |
134 |
|
|
} |
135 |
|
|
} |
136 |
|
|
|
137 |
|
|
return 0; |
138 |
|
|
} |
139 |
|
|
|
140 |
|
|
int |
141 |
|
|
limnPolyDataWriteIV(FILE *file, const limnPolyData *pld) { |
142 |
|
|
static const char me[]="limnPolyDataWriteIV"; |
143 |
|
|
unsigned int primIdx, xyzwIdx, rgbaIdx, normIdx, bitFlag, |
144 |
|
|
baseVertIdx; |
145 |
|
|
int haveStrips, haveTris, haveElse; |
146 |
|
|
double xyz[3], norm[3], len; |
147 |
|
|
|
148 |
|
|
if (!(file && pld)) { |
149 |
|
|
biffAddf(LIMN, "%s: got NULL pointer", me); |
150 |
|
|
return 1; |
151 |
|
|
} |
152 |
|
|
haveStrips = haveTris = haveElse = AIR_FALSE; |
153 |
|
|
for (primIdx=0; primIdx<pld->primNum; primIdx++) { |
154 |
|
|
int isTri, isStrip, isElse; |
155 |
|
|
isTri = limnPrimitiveTriangles == pld->type[primIdx]; |
156 |
|
|
isStrip = limnPrimitiveTriangleStrip == pld->type[primIdx]; |
157 |
|
|
isElse = !(isTri || isStrip); |
158 |
|
|
haveTris |= isTri; |
159 |
|
|
haveStrips |= isStrip; |
160 |
|
|
haveElse |= isElse; |
161 |
|
|
if (isElse) { |
162 |
|
|
biffAddf(LIMN, |
163 |
|
|
"%s: sorry, can only have %s or %s prims (prim[%u] is %s)", |
164 |
|
|
me, airEnumStr(limnPrimitive, limnPrimitiveTriangles), |
165 |
|
|
airEnumStr(limnPrimitive, limnPrimitiveTriangleStrip), |
166 |
|
|
primIdx, airEnumStr(limnPrimitive, pld->type[primIdx])); |
167 |
|
|
return 1; |
168 |
|
|
} |
169 |
|
|
} |
170 |
|
|
if (haveStrips && 1 != pld->primNum) { |
171 |
|
|
biffAddf(LIMN, "%s: sorry, can only have a single triangle strip", me); |
172 |
|
|
return 1; |
173 |
|
|
} |
174 |
|
|
|
175 |
|
|
fprintf(file, "#Inventor V2.0 ascii\n"); |
176 |
|
|
fprintf(file, "# written by Teem/limn\n\n"); |
177 |
|
|
fprintf(file, "Separator {\n"); |
178 |
|
|
fprintf(file, " Coordinate3 {\n"); |
179 |
|
|
fprintf(file, " point [\n"); |
180 |
|
|
if (haveStrips) { |
181 |
|
|
unsigned int vii; |
182 |
|
|
for (vii=0; vii<pld->icnt[0]; vii++) { |
183 |
|
|
xyzwIdx = (pld->indx)[vii]; |
184 |
|
|
ELL_34V_HOMOG(xyz, pld->xyzw + 4*xyzwIdx); |
185 |
|
|
fprintf(file, " %g %g %g%s\n", |
186 |
|
|
xyz[0], xyz[1], xyz[2], |
187 |
|
|
vii < pld->icnt[0]-1 ? "," : ""); |
188 |
|
|
} |
189 |
|
|
} else { |
190 |
|
|
for (xyzwIdx=0; xyzwIdx<pld->xyzwNum; xyzwIdx++) { |
191 |
|
|
ELL_34V_HOMOG(xyz, pld->xyzw + 4*xyzwIdx); |
192 |
|
|
fprintf(file, " %g %g %g%s\n", |
193 |
|
|
xyz[0], xyz[1], xyz[2], |
194 |
|
|
xyzwIdx < pld->xyzwNum-1 ? "," : ""); |
195 |
|
|
} |
196 |
|
|
} |
197 |
|
|
fprintf(file, " ]\n"); |
198 |
|
|
fprintf(file, " }\n"); |
199 |
|
|
|
200 |
|
|
bitFlag = limnPolyDataInfoBitFlag(pld); |
201 |
|
|
if (bitFlag & (1 << limnPolyDataInfoNorm)) { |
202 |
|
|
fprintf(file, " NormalBinding { value PER_VERTEX_INDEXED }\n"); |
203 |
|
|
fprintf(file, " Normal {\n"); |
204 |
|
|
fprintf(file, " vector [\n"); |
205 |
|
|
if (haveStrips) { |
206 |
|
|
unsigned int vii; |
207 |
|
|
for (vii=0; vii<pld->icnt[0]; vii++) { |
208 |
|
|
normIdx = (pld->indx)[vii]; |
209 |
|
|
ELL_3V_SET(norm, |
210 |
|
|
pld->norm[0 + 3*normIdx], |
211 |
|
|
pld->norm[1 + 3*normIdx], |
212 |
|
|
pld->norm[2 + 3*normIdx]); |
213 |
|
|
ELL_3V_NORM(norm, norm, len); |
214 |
|
|
fprintf(file, " %g %g %g%s\n", norm[0], norm[1], norm[2], |
215 |
|
|
vii < pld->icnt[0]-1 ? "," : ""); |
216 |
|
|
} |
217 |
|
|
} else { |
218 |
|
|
for (normIdx=0; normIdx<pld->normNum; normIdx++) { |
219 |
|
|
fprintf(file, " %g %g %g%s\n", |
220 |
|
|
pld->norm[0 + 3*normIdx], |
221 |
|
|
pld->norm[1 + 3*normIdx], |
222 |
|
|
pld->norm[2 + 3*normIdx], |
223 |
|
|
normIdx < pld->normNum-1 ? "," : ""); |
224 |
|
|
} |
225 |
|
|
} |
226 |
|
|
fprintf(file, " ]\n"); |
227 |
|
|
fprintf(file, " }\n"); |
228 |
|
|
} |
229 |
|
|
if (!haveStrips) { |
230 |
|
|
if (bitFlag & (1 << limnPolyDataInfoRGBA)) { |
231 |
|
|
fprintf(file, " MaterialBinding { value PER_VERTEX_INDEXED }\n"); |
232 |
|
|
fprintf(file, " Material {\n"); |
233 |
|
|
fprintf(file, " diffuseColor [\n"); |
234 |
|
|
for (rgbaIdx=0; rgbaIdx<pld->rgbaNum; rgbaIdx++) { |
235 |
|
|
fprintf(file, " %g %g %g%s\n", |
236 |
|
|
pld->rgba[0 + 4*rgbaIdx]/255.0, |
237 |
|
|
pld->rgba[1 + 4*rgbaIdx]/255.0, |
238 |
|
|
pld->rgba[2 + 4*rgbaIdx]/255.0, |
239 |
|
|
rgbaIdx < pld->rgbaNum-1 ? "," : ""); |
240 |
|
|
} |
241 |
|
|
fprintf(file, " ]\n"); |
242 |
|
|
fprintf(file, " }\n"); |
243 |
|
|
} |
244 |
|
|
} |
245 |
|
|
|
246 |
|
|
if (haveStrips) { |
247 |
|
|
fprintf(file, " TriangleStripSet {\n"); |
248 |
|
|
fprintf(file, " numVertices %u\n", pld->icnt[0]); |
249 |
|
|
fprintf(file, " }\n"); |
250 |
|
|
} else { |
251 |
|
|
fprintf(file, " IndexedFaceSet {\n"); |
252 |
|
|
fprintf(file, " coordIndex [\n"); |
253 |
|
|
|
254 |
|
|
baseVertIdx = 0; |
255 |
|
|
for (primIdx=0; primIdx<pld->primNum; primIdx++) { |
256 |
|
|
unsigned int triIdx, triNum, *indx3; |
257 |
|
|
triNum = pld->icnt[primIdx]/3; |
258 |
|
|
for (triIdx=0; triIdx<triNum; triIdx++) { |
259 |
|
|
indx3 = pld->indx + baseVertIdx + 3*triIdx; |
260 |
|
|
fprintf(file, " %u, %u, %u, -1%s\n", |
261 |
|
|
indx3[0], indx3[1], indx3[2], |
262 |
|
|
triIdx < triNum-1 ? "," : ""); |
263 |
|
|
} |
264 |
|
|
baseVertIdx += 3*triNum; |
265 |
|
|
} |
266 |
|
|
fprintf(file, " ]\n"); |
267 |
|
|
fprintf(file, " }\n"); |
268 |
|
|
} |
269 |
|
|
|
270 |
|
|
fprintf(file, "}\n"); |
271 |
|
|
|
272 |
|
|
return 0; |
273 |
|
|
} |
274 |
|
|
|
275 |
|
|
int |
276 |
|
|
limnObjectReadOFF(limnObject *obj, FILE *file) { |
277 |
|
|
static const char me[]="limnObjectReadOFF"; |
278 |
|
|
double vert[6]; |
279 |
|
|
char line[AIR_STRLEN_LARGE]; /* HEY: bad Gordon */ |
280 |
|
|
int lineCount, lookIdx, partIdx, idxTmp, faceNum, faceGot, got; |
281 |
|
|
unsigned int vertGot,vertNum; |
282 |
|
|
unsigned int ibuff[1024]; /* HEY: bad Gordon */ |
283 |
|
|
float fbuff[1024]; /* HEY: bad bad Gordon */ |
284 |
|
|
float lastRGB[3]={-1,-1,-1}; int lastLook; |
285 |
|
|
unsigned int lret; |
286 |
|
|
|
287 |
|
|
int *vertBase; |
288 |
|
|
airArray *vertBaseArr, *mop; |
289 |
|
|
airPtrPtrUnion appu; |
290 |
|
|
|
291 |
|
|
if (!( obj && file )) { |
292 |
|
|
biffAddf(LIMN, "%s: got NULL pointer", me); |
293 |
|
|
return 1; |
294 |
|
|
} |
295 |
|
|
vertBase = NULL; |
296 |
|
|
appu.i = &vertBase; |
297 |
|
|
vertBaseArr = airArrayNew(appu.v, NULL, sizeof(int), 128); |
298 |
|
|
mop = airMopNew(); |
299 |
|
|
airMopAdd(mop, vertBaseArr, (airMopper)airArrayNuke, airMopAlways); |
300 |
|
|
got = 0; |
301 |
|
|
lineCount = 0; |
302 |
|
|
do { |
303 |
|
|
if (!airOneLine(file, line, AIR_STRLEN_LARGE)) { |
304 |
|
|
biffAddf(LIMN, "%s: hit EOF before getting #vert #face #edge line", me); |
305 |
|
|
airMopError(mop); return 1; |
306 |
|
|
} |
307 |
|
|
lineCount++; |
308 |
|
|
got = airParseStrUI(ibuff, line, AIR_WHITESPACE, 3); |
309 |
|
|
} while (3 != got); |
310 |
|
|
vertNum = ibuff[0]; |
311 |
|
|
faceNum = ibuff[1]; |
312 |
|
|
|
313 |
|
|
/* read all vertex information */ |
314 |
|
|
lastLook = -1; |
315 |
|
|
partIdx = limnObjectPartAdd(obj); |
316 |
|
|
vertGot = 0; |
317 |
|
|
airArrayLenIncr(vertBaseArr, 1); |
318 |
|
|
vertBase[partIdx] = vertGot; |
319 |
|
|
while (vertGot < vertNum) { |
320 |
|
|
do { |
321 |
|
|
lret = airOneLine(file, line, AIR_STRLEN_LARGE); |
322 |
|
|
lineCount++; |
323 |
|
|
} while (1 == lret); |
324 |
|
|
if (!lret) { |
325 |
|
|
biffAddf(LIMN, |
326 |
|
|
"%s: (near line %d) hit EOF trying to read vert %d (of %d)", |
327 |
|
|
me, lineCount, vertGot, vertNum); |
328 |
|
|
airMopError(mop); return 1; |
329 |
|
|
} |
330 |
|
|
if (1 == sscanf(line, "### LIMN BEGIN PART %d", &idxTmp)) { |
331 |
|
|
if (idxTmp != 0) { |
332 |
|
|
partIdx = limnObjectPartAdd(obj); |
333 |
|
|
if (idxTmp != partIdx) { |
334 |
|
|
biffAddf(LIMN, "%s: got signal to start part %d, not %d", |
335 |
|
|
me, idxTmp, partIdx); |
336 |
|
|
airMopError(mop); return 1; |
337 |
|
|
} |
338 |
|
|
airArrayLenIncr(vertBaseArr, 1); |
339 |
|
|
vertBase[partIdx] = vertGot; |
340 |
|
|
} |
341 |
|
|
continue; |
342 |
|
|
} |
343 |
|
|
if (3 != airParseStrD(vert, line, AIR_WHITESPACE, 3)) { |
344 |
|
|
biffAddf(LIMN, "%s: couldn't parse 3 doubles from \"%s\" " |
345 |
|
|
"for vert %d (of %d)", |
346 |
|
|
me, line, vertGot, vertNum); |
347 |
|
|
airMopError(mop); return 1; |
348 |
|
|
} |
349 |
|
|
if (6 == airParseStrD(vert, line, AIR_WHITESPACE, 6)) { |
350 |
|
|
/* we could also parse an RGB color */ |
351 |
|
|
if (-1 == lastLook || !ELL_3V_EQUAL(lastRGB, vert+3)) { |
352 |
|
|
lookIdx = limnObjectLookAdd(obj); |
353 |
|
|
ELL_4V_SET(obj->look[lookIdx].rgba, |
354 |
|
|
AIR_CAST(float, vert[3]), |
355 |
|
|
AIR_CAST(float, vert[4]), |
356 |
|
|
AIR_CAST(float, vert[5]), |
357 |
|
|
1); |
358 |
|
|
lastLook = lookIdx; |
359 |
|
|
ELL_3V_COPY_TT(lastRGB, float, vert+3); |
360 |
|
|
} else { |
361 |
|
|
lookIdx = lastLook; |
362 |
|
|
} |
363 |
|
|
} else { |
364 |
|
|
lookIdx = 0; |
365 |
|
|
} |
366 |
|
|
/* |
367 |
|
|
fprintf(stderr, "line %d: vertGot = %d; lookIdx = %d; partIdx = %d\n", |
368 |
|
|
lineCount, vertGot, lookIdx, partIdx); |
369 |
|
|
*/ |
370 |
|
|
limnObjectVertexAdd(obj, partIdx, |
371 |
|
|
AIR_CAST(float, vert[0]), |
372 |
|
|
AIR_CAST(float, vert[1]), |
373 |
|
|
AIR_CAST(float, vert[2])); |
374 |
|
|
vertGot++; |
375 |
|
|
} |
376 |
|
|
/* read face information */ |
377 |
|
|
partIdx = 0; |
378 |
|
|
faceGot = 0; |
379 |
|
|
while (faceGot < faceNum) { |
380 |
|
|
do { |
381 |
|
|
lret = airOneLine(file, line, AIR_STRLEN_LARGE); |
382 |
|
|
lineCount++; |
383 |
|
|
} while (1 == lret); |
384 |
|
|
if (!lret) { |
385 |
|
|
biffAddf(LIMN, |
386 |
|
|
"%s: (near line %d) hit EOF trying to read face %d (of %d)", |
387 |
|
|
me, lineCount, faceGot, faceNum); |
388 |
|
|
airMopError(mop); return 1; |
389 |
|
|
} |
390 |
|
|
if (1 == sscanf(line, "### LIMN BEGIN PART %d", &idxTmp)) { |
391 |
|
|
if (idxTmp != 0) { |
392 |
|
|
partIdx += 1; |
393 |
|
|
if (idxTmp != partIdx) { |
394 |
|
|
biffAddf(LIMN, "%s: (near line %d) got signal to start " |
395 |
|
|
"part %d, not %d", |
396 |
|
|
me, lineCount, idxTmp, partIdx); |
397 |
|
|
airMopError(mop); return 1; |
398 |
|
|
} |
399 |
|
|
} |
400 |
|
|
continue; |
401 |
|
|
} |
402 |
|
|
if ('#' == line[0]) { |
403 |
|
|
/* its some other kind of comment line */ |
404 |
|
|
continue; |
405 |
|
|
} |
406 |
|
|
if (1 != sscanf(line, "%u", &vertNum)) { |
407 |
|
|
biffAddf(LIMN, "%s: (near line %d) can't get first int " |
408 |
|
|
"(#verts) from \"%s\" for face %d (of %d)", |
409 |
|
|
me, lineCount, line, faceGot, faceNum); |
410 |
|
|
airMopError(mop); return 1; |
411 |
|
|
} |
412 |
|
|
if (vertNum+1 != airParseStrUI(ibuff, line, AIR_WHITESPACE, vertNum+1)) { |
413 |
|
|
biffAddf(LIMN, "%s: (near line %d) couldn't parse %d ints from \"%s\" " |
414 |
|
|
"for face %d (of %d)", |
415 |
|
|
me, lineCount, vertNum+1, line, faceGot, faceNum); |
416 |
|
|
airMopError(mop); return 1; |
417 |
|
|
} |
418 |
|
|
if (vertNum+1+3 == airParseStrF(fbuff, line, |
419 |
|
|
AIR_WHITESPACE, vertNum+1+3)) { |
420 |
|
|
/* could also parse color */ |
421 |
|
|
if (-1 == lastLook || !ELL_3V_EQUAL(lastRGB, fbuff+vertNum+1)) { |
422 |
|
|
lookIdx = limnObjectLookAdd(obj); |
423 |
|
|
ELL_4V_SET(obj->look[lookIdx].rgba, fbuff[vertNum+1+0], |
424 |
|
|
fbuff[vertNum+1+1], fbuff[vertNum+1+2], 1); |
425 |
|
|
lastLook = lookIdx; |
426 |
|
|
ELL_3V_COPY(lastRGB, fbuff+vertNum+1); |
427 |
|
|
} else { |
428 |
|
|
lookIdx = lastLook; |
429 |
|
|
} |
430 |
|
|
} else { |
431 |
|
|
lookIdx = 0; |
432 |
|
|
} |
433 |
|
|
/* |
434 |
|
|
fprintf(stderr, "line %d: faceGot = %d; lookIdx = %d; partIdx = %d\n", |
435 |
|
|
lineCount, faceGot, lookIdx, partIdx); |
436 |
|
|
*/ |
437 |
|
|
limnObjectFaceAdd(obj, partIdx, lookIdx, vertNum, ibuff+1); |
438 |
|
|
faceGot++; |
439 |
|
|
} |
440 |
|
|
|
441 |
|
|
airMopOkay(mop); |
442 |
|
|
return 0; |
443 |
|
|
} |
444 |
|
|
|
445 |
|
|
/* |
446 |
|
|
http://www.npr.org/templates/story/story.php?storyId=4531695 |
447 |
|
|
*/ |
448 |
|
|
|
449 |
|
|
#define LMPD_MAGIC "LIMN0001" |
450 |
|
|
#define DEMARK_STR "====== " |
451 |
|
|
#define DEMARK_CHAR '=' |
452 |
|
|
#define NUM_STR "num:" |
453 |
|
|
#define INFO_STR "info:" |
454 |
|
|
#define TYPE_STR "type:" |
455 |
|
|
#define ICNT_STR "icnt:" |
456 |
|
|
#define INDX_STR "indx:" |
457 |
|
|
#define XYZW_STR "xyzw:" |
458 |
|
|
|
459 |
|
|
int |
460 |
|
|
limnPolyDataWriteLMPD(FILE *file, const limnPolyData *pld) { |
461 |
|
|
static const char me[]="limnPolyDataWriteLMPD"; |
462 |
|
|
char infoS[AIR_STRLEN_MED]; |
463 |
|
|
unsigned int primIdx, infoNum, flag, bit; |
464 |
|
|
Nrrd *nrrd; |
465 |
|
|
airArray *mop; |
466 |
|
|
|
467 |
|
|
if (!(file && pld)) { |
468 |
|
|
biffAddf(LIMN, "%s: got NULL pointer", me); |
469 |
|
|
return 1; |
470 |
|
|
} |
471 |
|
|
|
472 |
|
|
for (primIdx=0; primIdx<pld->primNum; primIdx++) { |
473 |
|
|
if (limnPrimitiveNoop == pld->type[primIdx]) { |
474 |
|
|
biffAddf(LIMN, "%s: sorry, can't save with prim[%u] type %s", me, |
475 |
|
|
primIdx, airEnumStr(limnPrimitive, pld->type[primIdx])); |
476 |
|
|
return 1; |
477 |
|
|
} |
478 |
|
|
} |
479 |
|
|
|
480 |
|
|
mop = airMopNew(); |
481 |
|
|
|
482 |
|
|
fprintf(file, "%s\n", LMPD_MAGIC); |
483 |
|
|
fprintf(file, "%s%s %u %u %u\n", DEMARK_STR, NUM_STR, |
484 |
|
|
pld->xyzwNum, pld->indxNum, pld->primNum); |
485 |
|
|
|
486 |
|
|
flag = limnPolyDataInfoBitFlag(pld); |
487 |
|
|
infoNum = 0; |
488 |
|
|
bit = 0; |
489 |
|
|
strcpy(infoS, ""); |
490 |
|
|
while (flag) { |
491 |
|
|
if (flag & 1) { |
492 |
|
|
infoNum += 1; |
493 |
|
|
strcat(infoS, airEnumStr(limnPolyDataInfo, bit)); |
494 |
|
|
strcat(infoS, "\n"); |
495 |
|
|
} |
496 |
|
|
flag /= 2; |
497 |
|
|
bit += 1; |
498 |
|
|
} |
499 |
|
|
fprintf(file, "%s%s %u\n%s", DEMARK_STR, INFO_STR, infoNum, infoS); |
500 |
|
|
|
501 |
|
|
fprintf(file, "%s%s\n", DEMARK_STR, TYPE_STR); |
502 |
|
|
for (primIdx=0; primIdx<pld->primNum; primIdx++) { |
503 |
|
|
fprintf(file, "%s\n", airEnumStr(limnPrimitive, pld->type[primIdx])); |
504 |
|
|
} |
505 |
|
|
fprintf(file, "%s%s\n", DEMARK_STR, ICNT_STR); |
506 |
|
|
for (primIdx=0; primIdx<pld->primNum; primIdx++) { |
507 |
|
|
fprintf(file, "%u\n", pld->icnt[primIdx]); |
508 |
|
|
} |
509 |
|
|
nrrd = nrrdNew(); |
510 |
|
|
airMopAdd(mop, nrrd, (airMopper)nrrdNix, airMopAlways); /* nix, not nuke */ |
511 |
|
|
|
512 |
|
|
fprintf(file, "%s%s\n", DEMARK_STR, INDX_STR); |
513 |
|
|
if (nrrdWrap_va(nrrd, pld->indx, nrrdTypeUInt, 1, pld->indxNum) |
514 |
|
|
|| nrrdWrite(file, nrrd, NULL)) { |
515 |
|
|
biffMovef(LIMN, NRRD, "%s: problem saving indx array", me); |
516 |
|
|
airMopError(mop); return 1; |
517 |
|
|
} |
518 |
|
|
fflush(file); |
519 |
|
|
fprintf(file, "\n"); |
520 |
|
|
|
521 |
|
|
fprintf(file, "%s%s\n", DEMARK_STR, XYZW_STR); |
522 |
|
|
if (nrrdWrap_va(nrrd, pld->xyzw, nrrdTypeFloat, 2, 4, pld->xyzwNum) |
523 |
|
|
|| nrrdWrite(file, nrrd, NULL)) { |
524 |
|
|
biffMovef(LIMN, NRRD, "%s: problem saving xyzw array", me); |
525 |
|
|
airMopError(mop); return 1; |
526 |
|
|
} |
527 |
|
|
fflush(file); |
528 |
|
|
fprintf(file, "\n"); |
529 |
|
|
|
530 |
|
|
if (infoNum) { |
531 |
|
|
flag = limnPolyDataInfoBitFlag(pld); |
532 |
|
|
bit = 0; |
533 |
|
|
while (flag) { |
534 |
|
|
if (flag & 1) { |
535 |
|
|
int E; |
536 |
|
|
fprintf(file, "%s%s %s\n", DEMARK_STR, INFO_STR, |
537 |
|
|
airEnumStr(limnPolyDataInfo, bit)); |
538 |
|
|
switch (bit) { |
539 |
|
|
case limnPolyDataInfoRGBA: |
540 |
|
|
E = nrrdWrap_va(nrrd, pld->rgba, nrrdTypeUChar, 2, 4, pld->rgbaNum); |
541 |
|
|
break; |
542 |
|
|
case limnPolyDataInfoNorm: |
543 |
|
|
E = nrrdWrap_va(nrrd, pld->norm, nrrdTypeFloat, 2, 3, pld->normNum); |
544 |
|
|
break; |
545 |
|
|
case limnPolyDataInfoTex2: |
546 |
|
|
E = nrrdWrap_va(nrrd, pld->tex2, nrrdTypeFloat, 2, 2, pld->tex2Num); |
547 |
|
|
break; |
548 |
|
|
case limnPolyDataInfoTang: |
549 |
|
|
E = nrrdWrap_va(nrrd, pld->tang, nrrdTypeFloat, 2, 3, pld->tangNum); |
550 |
|
|
break; |
551 |
|
|
default: |
552 |
|
|
biffAddf(LIMN, "%s: info %d (%s) not handled", me, bit, |
553 |
|
|
airEnumStr(limnPolyDataInfo, bit)); |
554 |
|
|
airMopError(mop); return 1; |
555 |
|
|
break; |
556 |
|
|
} |
557 |
|
|
if (E || nrrdWrite(file, nrrd, NULL)) { |
558 |
|
|
biffMovef(LIMN, NRRD, "%s: problem saving %s info", |
559 |
|
|
me, airEnumStr(limnPolyDataInfo, bit)); |
560 |
|
|
airMopError(mop); return 1; |
561 |
|
|
} |
562 |
|
|
fflush(file); |
563 |
|
|
fprintf(file, "\n"); |
564 |
|
|
} |
565 |
|
|
flag /= 2; |
566 |
|
|
bit += 1; |
567 |
|
|
} |
568 |
|
|
} |
569 |
|
|
|
570 |
|
|
airMopOkay(mop); |
571 |
|
|
return 0; |
572 |
|
|
} |
573 |
|
|
|
574 |
|
|
/* |
575 |
|
|
******** limnPolyDataReadLMPD |
576 |
|
|
** |
577 |
|
|
** reads a limnPolyData from an LMPD file |
578 |
|
|
** |
579 |
|
|
** HEY: this was written in a hurry, is pretty hacky, and so it |
580 |
|
|
** needs some serious clean-up |
581 |
|
|
*/ |
582 |
|
|
int |
583 |
|
|
limnPolyDataReadLMPD(limnPolyData *pld, FILE *file) { |
584 |
|
|
static const char me[]="limnPolyDatReadLMPD"; |
585 |
|
|
char line[AIR_STRLEN_MED], name[AIR_STRLEN_MED], *tmp; |
586 |
|
|
unsigned int vertNum, indxNum, primNum, primIdx, lineLen, |
587 |
|
|
infoNum, infoIdx, info, flag; |
588 |
|
|
Nrrd *nrrd; |
589 |
|
|
airArray *mop; |
590 |
|
|
int hackhack, tmpChar; |
591 |
|
|
|
592 |
|
|
if (!(pld && file)) { |
593 |
|
|
biffAddf(LIMN, "%s: got NULL pointer", me); |
594 |
|
|
return 1; |
595 |
|
|
} |
596 |
|
|
|
597 |
|
|
sprintf(name, "magic"); |
598 |
|
|
lineLen = airOneLine(file, line, AIR_STRLEN_MED); |
599 |
|
|
if (!lineLen) { |
600 |
|
|
biffAddf(LIMN, "%s: didn't get %s line", me, name); |
601 |
|
|
return 1; |
602 |
|
|
} |
603 |
|
|
if (strcmp(line, LMPD_MAGIC)) { |
604 |
|
|
biffAddf(LIMN, "%s: %s line \"%s\" not expected \"%s\"", |
605 |
|
|
me, name, line, LMPD_MAGIC); |
606 |
|
|
return 1; |
607 |
|
|
} |
608 |
|
|
|
609 |
|
|
sprintf(name, "nums"); |
610 |
|
|
lineLen = airOneLine(file, line, AIR_STRLEN_MED); |
611 |
|
|
if (!lineLen) { |
612 |
|
|
biffAddf(LIMN, "%s: didn't get %s line", me, name); |
613 |
|
|
return 1; |
614 |
|
|
} |
615 |
|
|
if (strncmp(line, DEMARK_STR NUM_STR, strlen(DEMARK_STR NUM_STR))) { |
616 |
|
|
biffAddf(LIMN, "%s: %s line \"%s\" didn't start w/ expected \"%s\"", |
617 |
|
|
me, name, line, NUM_STR); |
618 |
|
|
return 1; |
619 |
|
|
} |
620 |
|
|
tmp = line + strlen(DEMARK_STR NUM_STR); |
621 |
|
|
if (3 != sscanf(tmp, " %u %u %u", &vertNum, &indxNum, &primNum)) { |
622 |
|
|
biffAddf(LIMN, "%s: couldn't parse \"%s\" as 3 uints on %s line", |
623 |
|
|
me, tmp, name); |
624 |
|
|
return 1; |
625 |
|
|
} |
626 |
|
|
|
627 |
|
|
sprintf(name, "info"); |
628 |
|
|
lineLen = airOneLine(file, line, AIR_STRLEN_MED); |
629 |
|
|
if (!lineLen) { |
630 |
|
|
biffAddf(LIMN, "%s: didn't get %s line", me, name); |
631 |
|
|
return 1; |
632 |
|
|
} |
633 |
|
|
if (strncmp(line, DEMARK_STR INFO_STR, strlen(DEMARK_STR INFO_STR))) { |
634 |
|
|
biffAddf(LIMN, "%s: %s line \"%s\" didn't start w/ expected \"%s\"", |
635 |
|
|
me, name, line, DEMARK_STR INFO_STR); |
636 |
|
|
return 1; |
637 |
|
|
} |
638 |
|
|
tmp = line + strlen(DEMARK_STR INFO_STR); |
639 |
|
|
if (1 != sscanf(tmp, " %u", &infoNum)) { |
640 |
|
|
biffAddf(LIMN, "%s: couldn't parse \"%s\" as 1 uints on %s line", |
641 |
|
|
me, tmp, name); |
642 |
|
|
return 1; |
643 |
|
|
} |
644 |
|
|
flag = 0; |
645 |
|
|
for (infoIdx=0; infoIdx<infoNum; infoIdx++) { |
646 |
|
|
lineLen = airOneLine(file, line, AIR_STRLEN_MED); |
647 |
|
|
if (!lineLen) { |
648 |
|
|
biffAddf(LIMN, "%s: didn't get %s line %u/%u", |
649 |
|
|
me, name, infoIdx, infoNum); |
650 |
|
|
return 1; |
651 |
|
|
} |
652 |
|
|
info = airEnumVal(limnPolyDataInfo, line); |
653 |
|
|
if (!info) { |
654 |
|
|
biffAddf(LIMN, "%s: couldn't parse \"%s\" %s line %u/%u", |
655 |
|
|
me, line, name, infoIdx, infoNum); |
656 |
|
|
return 1; |
657 |
|
|
} |
658 |
|
|
flag |= (1 << info); |
659 |
|
|
} |
660 |
|
|
|
661 |
|
|
/* finally, allocate the polydata */ |
662 |
|
|
if (limnPolyDataAlloc(pld, flag, vertNum, indxNum, primNum)) { |
663 |
|
|
biffAddf(LIMN, "%s: couldn't allocate polydata", me); |
664 |
|
|
return 1; |
665 |
|
|
} |
666 |
|
|
/* actually, caller owns pld, so we don't register it with mop */ |
667 |
|
|
|
668 |
|
|
sprintf(name, "type"); |
669 |
|
|
lineLen = airOneLine(file, line, AIR_STRLEN_MED); |
670 |
|
|
if (!lineLen) { |
671 |
|
|
biffAddf(LIMN, "%s: didn't get %s line", me, name); |
672 |
|
|
return 1; |
673 |
|
|
} |
674 |
|
|
if (strcmp(line, DEMARK_STR TYPE_STR)) { |
675 |
|
|
biffAddf(LIMN, "%s: %s line \"%s\" not expected \"%s\"", |
676 |
|
|
me, name, line, DEMARK_STR TYPE_STR); |
677 |
|
|
return 1; |
678 |
|
|
} |
679 |
|
|
for (primIdx=0; primIdx<primNum; primIdx++) { |
680 |
|
|
lineLen = airOneLine(file, line, AIR_STRLEN_MED); |
681 |
|
|
if (!lineLen) { |
682 |
|
|
biffAddf(LIMN, "%s: didn't get %s line %u/%u", |
683 |
|
|
me, name, primIdx, primNum); |
684 |
|
|
return 1; |
685 |
|
|
} |
686 |
|
|
pld->type[primIdx] = airEnumVal(limnPrimitive, line); |
687 |
|
|
if (!(pld->type[primIdx])) { |
688 |
|
|
biffAddf(LIMN, "%s: couldn't parse \"%s\" %s line %u/%u", |
689 |
|
|
me, line, name, primIdx, primNum); |
690 |
|
|
return 1; |
691 |
|
|
} |
692 |
|
|
} |
693 |
|
|
|
694 |
|
|
sprintf(name, "icnt"); |
695 |
|
|
lineLen = airOneLine(file, line, AIR_STRLEN_MED); |
696 |
|
|
if (!lineLen) { |
697 |
|
|
biffAddf(LIMN, "%s: didn't get %s line", me, name); |
698 |
|
|
return 1; |
699 |
|
|
} |
700 |
|
|
if (strcmp(line, DEMARK_STR ICNT_STR)) { |
701 |
|
|
biffAddf(LIMN, "%s: %s line \"%s\" not expected \"%s\"", |
702 |
|
|
me, name, line, DEMARK_STR ICNT_STR); |
703 |
|
|
return 1; |
704 |
|
|
} |
705 |
|
|
for (primIdx=0; primIdx<primNum; primIdx++) { |
706 |
|
|
lineLen = airOneLine(file, line, AIR_STRLEN_MED); |
707 |
|
|
if (!lineLen) { |
708 |
|
|
biffAddf(LIMN, "%s: didn't get %s line %u/%u", |
709 |
|
|
me, name, primIdx, primNum); |
710 |
|
|
return 1; |
711 |
|
|
} |
712 |
|
|
if (1 != sscanf(line, "%u", &(pld->icnt[primIdx]))) { |
713 |
|
|
biffAddf(LIMN, "%s: couldn't parse \"%s\" %s line %u/%u", |
714 |
|
|
me, line, name, primIdx, primNum); |
715 |
|
|
return 1; |
716 |
|
|
} |
717 |
|
|
} |
718 |
|
|
|
719 |
|
|
sprintf(name, "indx"); |
720 |
|
|
lineLen = airOneLine(file, line, AIR_STRLEN_MED); |
721 |
|
|
if (!lineLen) { |
722 |
|
|
biffAddf(LIMN, "%s: didn't get %s line", me, name); |
723 |
|
|
return 1; |
724 |
|
|
} |
725 |
|
|
if (strcmp(line, DEMARK_STR INDX_STR)) { |
726 |
|
|
biffAddf(LIMN, "%s: %s line \"%s\" not expected \"%s\"", |
727 |
|
|
me, name, line, DEMARK_STR ICNT_STR); |
728 |
|
|
return 1; |
729 |
|
|
} |
730 |
|
|
|
731 |
|
|
/* NOW its finally time to create the mop */ |
732 |
|
|
mop = airMopNew(); |
733 |
|
|
nrrd = nrrdNew(); |
734 |
|
|
airMopAdd(mop, nrrd, (airMopper)nrrdNuke, airMopAlways); |
735 |
|
|
/* HEY HEY HEY HOLY CRAP! |
736 |
|
|
** why the hell isn't the verbosity level a field in NrrdIoState ?!?! |
737 |
|
|
** THIS NEES TO BE FIXED (in nrrd) ASAP! |
738 |
|
|
*/ |
739 |
|
|
hackhack = nrrdStateVerboseIO; |
740 |
|
|
nrrdStateVerboseIO = 0; |
741 |
|
|
if (nrrdRead(nrrd, file, NULL)) { |
742 |
|
|
biffMovef(LIMN, NRRD, "%s: trouble reading %s data", me, name); |
743 |
|
|
airMopError(mop); return 1; |
744 |
|
|
} |
745 |
|
|
if (!(nrrdTypeUInt == nrrd->type |
746 |
|
|
&& 1 == nrrd->dim |
747 |
|
|
&& indxNum == nrrd->axis[0].size)) { |
748 |
|
|
biffAddf(LIMN, "%s: didn't get 1-D %s-type %u-sample array " |
749 |
|
|
"(got %u-D %s-type %u-by-? array)", me, |
750 |
|
|
airEnumStr(nrrdType, nrrdTypeUInt), |
751 |
|
|
AIR_CAST(unsigned int, indxNum), |
752 |
|
|
nrrd->dim, |
753 |
|
|
airEnumStr(nrrdType, nrrd->type), |
754 |
|
|
AIR_CAST(unsigned int, nrrd->axis[0].size)); |
755 |
|
|
airMopError(mop); return 1; |
756 |
|
|
} |
757 |
|
|
/* now copy the data */ |
758 |
|
|
memcpy(pld->indx, nrrd->data, nrrdElementSize(nrrd)*nrrdElementNumber(nrrd)); |
759 |
|
|
do { |
760 |
|
|
tmpChar = getc(file); |
761 |
|
|
if (EOF == tmpChar) { |
762 |
|
|
biffAddf(LIMN, "%s: hit EOF seeking to begin next line", me); |
763 |
|
|
airMopError(mop); return 1; |
764 |
|
|
} |
765 |
|
|
} while (DEMARK_CHAR != tmpChar); |
766 |
|
|
ungetc(tmpChar, file); |
767 |
|
|
|
768 |
|
|
sprintf(name, "xyzw"); |
769 |
|
|
lineLen = airOneLine(file, line, AIR_STRLEN_MED); |
770 |
|
|
if (!lineLen) { |
771 |
|
|
biffAddf(LIMN, "%s: didn't get %s line", me, name); |
772 |
|
|
return 1; |
773 |
|
|
} |
774 |
|
|
if (strcmp(line, DEMARK_STR XYZW_STR)) { |
775 |
|
|
biffAddf(LIMN, "%s: %s line \"%s\" not expected \"%s\"", |
776 |
|
|
me, name, line, DEMARK_STR XYZW_STR); |
777 |
|
|
return 1; |
778 |
|
|
} |
779 |
|
|
if (nrrdRead(nrrd, file, NULL)) { |
780 |
|
|
biffMovef(LIMN, NRRD, "%s: trouble reading %s data", me, name); |
781 |
|
|
airMopError(mop); return 1; |
782 |
|
|
} |
783 |
|
|
if (!(nrrdTypeFloat == nrrd->type |
784 |
|
|
&& 2 == nrrd->dim |
785 |
|
|
&& 4 == nrrd->axis[0].size |
786 |
|
|
&& vertNum == nrrd->axis[1].size)) { |
787 |
|
|
biffAddf(LIMN, "%s: didn't get 2-D %s-type 4-by-%u array " |
788 |
|
|
"(got %u-D %s-type %u-by-%u array)", me, |
789 |
|
|
airEnumStr(nrrdType, nrrdTypeFloat), |
790 |
|
|
AIR_CAST(unsigned int, vertNum), |
791 |
|
|
nrrd->dim, |
792 |
|
|
airEnumStr(nrrdType, nrrd->type), |
793 |
|
|
AIR_CAST(unsigned int, nrrd->axis[0].size), |
794 |
|
|
AIR_CAST(unsigned int, nrrd->axis[1].size)); |
795 |
|
|
airMopError(mop); return 1; |
796 |
|
|
} |
797 |
|
|
/* now copy the data */ |
798 |
|
|
memcpy(pld->xyzw, nrrd->data, nrrdElementSize(nrrd)*nrrdElementNumber(nrrd)); |
799 |
|
|
|
800 |
|
|
if (infoNum) { |
801 |
|
|
int wantType; |
802 |
|
|
unsigned int wantSize; |
803 |
|
|
void *data; |
804 |
|
|
for (infoIdx=0; infoIdx<infoNum; infoIdx++) { |
805 |
|
|
do { |
806 |
|
|
tmpChar = getc(file); |
807 |
|
|
if (EOF == tmpChar) { |
808 |
|
|
biffAddf(LIMN, "%s: hit EOF seeking to begin next line", me); |
809 |
|
|
airMopError(mop); return 1; |
810 |
|
|
} |
811 |
|
|
} while (DEMARK_CHAR != tmpChar); |
812 |
|
|
ungetc(tmpChar, file); |
813 |
|
|
lineLen = airOneLine(file, line, AIR_STRLEN_MED); |
814 |
|
|
if (!lineLen) { |
815 |
|
|
biffAddf(LIMN, "%s: didn't get %s line %u/%u", me, |
816 |
|
|
INFO_STR, infoIdx, infoNum); |
817 |
|
|
return 1; |
818 |
|
|
} |
819 |
|
|
if (strncmp(line, DEMARK_STR INFO_STR, strlen(DEMARK_STR INFO_STR))) { |
820 |
|
|
biffAddf(LIMN, "%s: %s line \"%s\" not expected \"%s\"", |
821 |
|
|
me, INFO_STR, line, DEMARK_STR INFO_STR); |
822 |
|
|
return 1; |
823 |
|
|
} |
824 |
|
|
tmp = line + strlen(DEMARK_STR INFO_STR) + strlen(" "); |
825 |
|
|
info = airEnumVal(limnPolyDataInfo, tmp); |
826 |
|
|
if (!info) { |
827 |
|
|
biffAddf(LIMN, "%s: couldn't parse \"%s\" as %s in %s line \"%s\"", |
828 |
|
|
me, tmp, limnPolyDataInfo->name, INFO_STR, line); |
829 |
|
|
return 1; |
830 |
|
|
} |
831 |
|
|
if (nrrdRead(nrrd, file, NULL)) { |
832 |
|
|
biffMovef(LIMN, NRRD, "%s: trouble reading %s %s data", |
833 |
|
|
me, INFO_STR, tmp); |
834 |
|
|
airMopError(mop); return 1; |
835 |
|
|
} |
836 |
|
|
switch (info) { |
837 |
|
|
case limnPolyDataInfoRGBA: |
838 |
|
|
wantType = nrrdTypeUChar; |
839 |
|
|
wantSize = 4; |
840 |
|
|
data = pld->rgba; |
841 |
|
|
break; |
842 |
|
|
case limnPolyDataInfoNorm: |
843 |
|
|
wantType = nrrdTypeFloat; |
844 |
|
|
wantSize = 3; |
845 |
|
|
data = pld->norm; |
846 |
|
|
break; |
847 |
|
|
case limnPolyDataInfoTex2: |
848 |
|
|
wantType = nrrdTypeFloat; |
849 |
|
|
wantSize = 2; |
850 |
|
|
data = pld->tex2; |
851 |
|
|
break; |
852 |
|
|
case limnPolyDataInfoTang: |
853 |
|
|
wantType = nrrdTypeFloat; |
854 |
|
|
wantSize = 3; |
855 |
|
|
data = pld->tang; |
856 |
|
|
break; |
857 |
|
|
default: |
858 |
|
|
biffAddf(LIMN, "%s: info %d (%s) not handled", me, info, |
859 |
|
|
airEnumStr(limnPolyDataInfo, info)); |
860 |
|
|
airMopError(mop); return 1; |
861 |
|
|
break; |
862 |
|
|
} |
863 |
|
|
if (!(wantType == nrrd->type |
864 |
|
|
&& 2 == nrrd->dim |
865 |
|
|
&& wantSize == nrrd->axis[0].size |
866 |
|
|
&& vertNum == nrrd->axis[1].size)) { |
867 |
|
|
biffAddf(LIMN, "%s: didn't get 2-D %s-type %u-by-%u array " |
868 |
|
|
"(got %u-D %s-type %u-by-%u-by-? array)", me, |
869 |
|
|
airEnumStr(nrrdType, wantType), |
870 |
|
|
wantSize, AIR_CAST(unsigned int, vertNum), |
871 |
|
|
nrrd->dim, |
872 |
|
|
airEnumStr(nrrdType, nrrd->type), |
873 |
|
|
AIR_CAST(unsigned int, nrrd->axis[0].size), |
874 |
|
|
AIR_CAST(unsigned int, nrrd->axis[1].size)); |
875 |
|
|
airMopError(mop); return 1; |
876 |
|
|
} |
877 |
|
|
/* now copy the data */ |
878 |
|
|
memcpy(data, nrrd->data, nrrdElementSize(nrrd)*nrrdElementNumber(nrrd)); |
879 |
|
|
} |
880 |
|
|
} |
881 |
|
|
|
882 |
|
|
airMopOkay(mop); |
883 |
|
|
nrrdStateVerboseIO = hackhack; |
884 |
|
|
return 0; |
885 |
|
|
} |
886 |
|
|
|
887 |
|
|
int |
888 |
|
|
_limnHestPolyDataLMPDParse(void *ptr, char *str, char err[AIR_STRLEN_HUGE]) { |
889 |
|
|
static const char me[] = "_limnHestPolyDataLMPDParse"; |
890 |
|
|
char *nerr; |
891 |
|
|
limnPolyData **lpldP; |
892 |
|
|
airArray *mop; |
893 |
|
|
FILE *file; |
894 |
|
|
|
895 |
|
|
if (!(ptr && str)) { |
896 |
|
|
sprintf(err, "%s: got NULL pointer", me); |
897 |
|
|
return 1; |
898 |
|
|
} |
899 |
|
|
|
900 |
|
|
lpldP = (limnPolyData **)ptr; |
901 |
|
|
if (!strlen(str)) { |
902 |
|
|
/* got empty filename; user didn't really want data, that's okay*/ |
903 |
|
|
*lpldP = NULL; |
904 |
|
|
return 0; |
905 |
|
|
} |
906 |
|
|
|
907 |
|
|
mop = airMopNew(); |
908 |
|
|
if (!( file = airFopen(str, stdin, "rb") )) { |
909 |
|
|
sprintf(err, "%s: couldn't fopen(\"%s\",\"rb\"): %s", |
910 |
|
|
me, str, strerror(errno)); |
911 |
|
|
biffAdd(LIMN, err); airMopError(mop); return 1; |
912 |
|
|
} |
913 |
|
|
airMopAdd(mop, file, (airMopper)airFclose, airMopAlways); |
914 |
|
|
*lpldP = limnPolyDataNew(); |
915 |
|
|
airMopAdd(mop, *lpldP, (airMopper)limnPolyDataNix, airMopOnError); |
916 |
|
|
if (limnPolyDataReadLMPD(*lpldP, file)) { |
917 |
|
|
airMopAdd(mop, nerr = biffGetDone(LIMN), airFree, airMopOnError); |
918 |
|
|
airStrcpy(err, AIR_STRLEN_HUGE, nerr); |
919 |
|
|
airMopError(mop); |
920 |
|
|
return 1; |
921 |
|
|
} |
922 |
|
|
airMopOkay(mop); |
923 |
|
|
return 0; |
924 |
|
|
} |
925 |
|
|
|
926 |
|
|
hestCB |
927 |
|
|
_limnHestPolyDataLMPD = { |
928 |
|
|
sizeof(limnPolyData *), |
929 |
|
|
"polydata", |
930 |
|
|
_limnHestPolyDataLMPDParse, |
931 |
|
|
(airMopper)limnPolyDataNix |
932 |
|
|
}; |
933 |
|
|
|
934 |
|
|
hestCB * |
935 |
|
|
limnHestPolyDataLMPD = &_limnHestPolyDataLMPD; |
936 |
|
|
|
937 |
|
|
int |
938 |
|
|
_limnHestPolyDataOFFParse(void *ptr, char *str, char err[AIR_STRLEN_HUGE]) { |
939 |
|
|
static const char me[] = "_limnHestPolyDataOFFParse"; |
940 |
|
|
char *nerr; |
941 |
|
|
limnPolyData **lpldP; |
942 |
|
|
airArray *mop; |
943 |
|
|
FILE *file; |
944 |
|
|
|
945 |
|
|
if (!(ptr && str)) { |
946 |
|
|
sprintf(err, "%s: got NULL pointer", me); |
947 |
|
|
return 1; |
948 |
|
|
} |
949 |
|
|
|
950 |
|
|
lpldP = (limnPolyData **)ptr; |
951 |
|
|
if (!strlen(str)) { |
952 |
|
|
/* got empty filename; user didn't really want data, that's okay*/ |
953 |
|
|
*lpldP = NULL; |
954 |
|
|
return 0; |
955 |
|
|
} |
956 |
|
|
|
957 |
|
|
mop = airMopNew(); |
958 |
|
|
if (!( file = airFopen(str, stdin, "rb") )) { |
959 |
|
|
sprintf(err, "%s: couldn't fopen(\"%s\",\"rb\"): %s", |
960 |
|
|
me, str, strerror(errno)); |
961 |
|
|
airMopError(mop); return 1; |
962 |
|
|
} |
963 |
|
|
airMopAdd(mop, file, (airMopper)airFclose, airMopAlways); |
964 |
|
|
*lpldP = limnPolyDataNew(); |
965 |
|
|
airMopAdd(mop, *lpldP, (airMopper)limnPolyDataNix, airMopOnError); |
966 |
|
|
if (limnPolyDataReadOFF(*lpldP, file)) { |
967 |
|
|
airMopAdd(mop, nerr = biffGetDone(LIMN), airFree, airMopOnError); |
968 |
|
|
strncpy(err, nerr, AIR_STRLEN_HUGE-1); |
969 |
|
|
airMopError(mop); |
970 |
|
|
return 1; |
971 |
|
|
} |
972 |
|
|
airMopOkay(mop); |
973 |
|
|
return 0; |
974 |
|
|
} |
975 |
|
|
|
976 |
|
|
hestCB |
977 |
|
|
_limnHestPolyDataOFF = { |
978 |
|
|
sizeof(limnPolyData *), |
979 |
|
|
"polydata", |
980 |
|
|
_limnHestPolyDataOFFParse, |
981 |
|
|
(airMopper)limnPolyDataNix |
982 |
|
|
}; |
983 |
|
|
|
984 |
|
|
hestCB * |
985 |
|
|
limnHestPolyDataOFF = &_limnHestPolyDataOFF; |
986 |
|
|
|
987 |
|
|
int |
988 |
|
|
limnPolyDataWriteVTK(FILE *file, const limnPolyData *pld) { |
989 |
|
|
static const char me[]="limnPolyDataWriteVTK"; |
990 |
|
|
unsigned int pntIdx, prmIdx, *indx, idxNum; |
991 |
|
|
int linesOnly; |
992 |
|
|
|
993 |
|
|
if (!(file && pld)) { |
994 |
|
|
biffAddf(LIMN, "%s: got NULL pointer", me); |
995 |
|
|
return 1; |
996 |
|
|
} |
997 |
|
|
fprintf(file, "# vtk DataFile Version 2.0\n"); |
998 |
|
|
fprintf(file, "limnPolyData\n"); |
999 |
|
|
fprintf(file, "ASCII\n"); |
1000 |
|
|
fprintf(file, "DATASET POLYDATA\n"); |
1001 |
|
|
fprintf(file, "POINTS %u float\n", pld->xyzwNum); |
1002 |
|
|
for (pntIdx=0; pntIdx<pld->xyzwNum; pntIdx++) { |
1003 |
|
|
float xyz[3]; |
1004 |
|
|
ELL_34V_HOMOG(xyz, pld->xyzw + 4*pntIdx); |
1005 |
|
|
fprintf(file, "%f %f %f\n", xyz[0], xyz[1], xyz[2]); |
1006 |
|
|
} |
1007 |
|
|
|
1008 |
|
|
fprintf(file, "\n"); |
1009 |
|
|
|
1010 |
|
|
/* first check if its only lines... */ |
1011 |
|
|
linesOnly = AIR_TRUE; |
1012 |
|
|
for (prmIdx=0; prmIdx<pld->primNum; prmIdx++) { |
1013 |
|
|
linesOnly &= (limnPrimitiveLineStrip == pld->type[prmIdx]); |
1014 |
|
|
} |
1015 |
|
|
if (linesOnly) { |
1016 |
|
|
fprintf(file, "LINES %u %u\n", pld->primNum, pld->primNum + pld->indxNum); |
1017 |
|
|
indx = pld->indx; |
1018 |
|
|
for (prmIdx=0; prmIdx<pld->primNum; prmIdx++) { |
1019 |
|
|
unsigned int ii; |
1020 |
|
|
idxNum = pld->icnt[prmIdx]; |
1021 |
|
|
fprintf(file, "%u", idxNum); |
1022 |
|
|
for (ii=0; ii<idxNum; ii++) { |
1023 |
|
|
fprintf(file, " %u", indx[ii]); |
1024 |
|
|
} |
1025 |
|
|
fprintf(file, "\n"); |
1026 |
|
|
indx += idxNum; |
1027 |
|
|
} |
1028 |
|
|
} else { |
1029 |
|
|
indx = pld->indx; |
1030 |
|
|
for (prmIdx=0; prmIdx<pld->primNum; prmIdx++) { |
1031 |
|
|
unsigned int triNum, triIdx; |
1032 |
|
|
idxNum = pld->icnt[prmIdx]; |
1033 |
|
|
switch (pld->type[prmIdx]) { |
1034 |
|
|
case limnPrimitiveTriangleFan: |
1035 |
|
|
biffAddf(LIMN, "%s: %s prims (prim[%u]) not supported in VTK?", |
1036 |
|
|
me, airEnumStr(limnPrimitive, pld->type[prmIdx]), prmIdx); |
1037 |
|
|
return 1; |
1038 |
|
|
break; |
1039 |
|
|
case limnPrimitiveQuads: |
1040 |
|
|
case limnPrimitiveTriangleStrip: |
1041 |
|
|
biffAddf(LIMN, "%s: sorry, saving %s prims (prim[%u]) not implemented", |
1042 |
|
|
me, airEnumStr(limnPrimitive, pld->type[prmIdx]), prmIdx); |
1043 |
|
|
return 1; |
1044 |
|
|
break; |
1045 |
|
|
case limnPrimitiveLineStrip: |
1046 |
|
|
biffAddf(LIMN, "%s: confusion", me); |
1047 |
|
|
return 1; |
1048 |
|
|
break; |
1049 |
|
|
case limnPrimitiveTriangles: |
1050 |
|
|
triNum = idxNum/3; |
1051 |
|
|
fprintf(file, "POLYGONS %u %u\n", triNum, triNum + idxNum); |
1052 |
|
|
for (triIdx=0; triIdx<triNum; triIdx++) { |
1053 |
|
|
fprintf(file, "3 %u %u %u\n", |
1054 |
|
|
indx[0 + 3*triIdx], indx[1 + 3*triIdx], indx[2 + 3*triIdx]); |
1055 |
|
|
} |
1056 |
|
|
break; |
1057 |
|
|
default: |
1058 |
|
|
biffAddf(LIMN, "%s: sorry, type %s (prim %u) not handled here", me, |
1059 |
|
|
airEnumStr(limnPrimitive, pld->type[prmIdx]), prmIdx); |
1060 |
|
|
return 1; |
1061 |
|
|
break; |
1062 |
|
|
} |
1063 |
|
|
fprintf(file, "\n"); |
1064 |
|
|
indx += idxNum; |
1065 |
|
|
} |
1066 |
|
|
} |
1067 |
|
|
|
1068 |
|
|
return 0; |
1069 |
|
|
} |
1070 |
|
|
|
1071 |
|
|
/* |
1072 |
|
|
******** limnPolyDataReadOFF |
1073 |
|
|
** |
1074 |
|
|
** HEY: this has to be re-written with different allocation strategies |
1075 |
|
|
** if it is to support anything other than a single limnPrimitiveTriangles |
1076 |
|
|
*/ |
1077 |
|
|
int |
1078 |
|
|
limnPolyDataReadOFF(limnPolyData *pld, FILE *file) { |
1079 |
|
|
static const char me[]="limnPolyDataReadOFF"; |
1080 |
|
|
char line[AIR_STRLEN_LARGE]; /* HEY: bad Gordon */ |
1081 |
|
|
unsigned int num[3], xyzwNum, xyzwGot, |
1082 |
|
|
faceNum, faceGot, lineCount, got, lret; |
1083 |
|
|
|
1084 |
|
|
if (!( pld && file )) { |
1085 |
|
|
biffAddf(LIMN, "%s: got NULL pointer", me); |
1086 |
|
|
return 1; |
1087 |
|
|
} |
1088 |
|
|
|
1089 |
|
|
/* HEY: this just snarfs lines until it parses 3 uints, |
1090 |
|
|
disregarding whether the "OFF" magic was actually there! */ |
1091 |
|
|
got = 0; |
1092 |
|
|
lineCount = 0; |
1093 |
|
|
do { |
1094 |
|
|
if (!airOneLine(file, line, AIR_STRLEN_LARGE)) { |
1095 |
|
|
biffAddf(LIMN, "%s: hit EOF before getting #vert #face #edge line", me); |
1096 |
|
|
return 1; |
1097 |
|
|
} |
1098 |
|
|
lineCount++; |
1099 |
|
|
got = airParseStrUI(num, line, AIR_WHITESPACE, 3); |
1100 |
|
|
} while (3 != got); |
1101 |
|
|
xyzwNum = num[0]; |
1102 |
|
|
faceNum = num[1]; |
1103 |
|
|
|
1104 |
|
|
/* allocate */ |
1105 |
|
|
if (limnPolyDataAlloc(pld, 0 /* no extra info */, |
1106 |
|
|
xyzwNum, 3*faceNum, 1)) { |
1107 |
|
|
biffAddf(LIMN, "%s: couldn't allocate", me); |
1108 |
|
|
return 1; |
1109 |
|
|
} |
1110 |
|
|
|
1111 |
|
|
/* read all vertex information */ |
1112 |
|
|
xyzwGot = 0; |
1113 |
|
|
while (xyzwGot < xyzwNum) { |
1114 |
|
|
float *xyzw; |
1115 |
|
|
do { |
1116 |
|
|
lret = airOneLine(file, line, AIR_STRLEN_LARGE); |
1117 |
|
|
lineCount++; |
1118 |
|
|
} while (1 == lret); |
1119 |
|
|
if (!lret) { |
1120 |
|
|
biffAddf(LIMN, |
1121 |
|
|
"%s: (near line %d) hit EOF trying to read vert %d (of %d)", |
1122 |
|
|
me, lineCount, xyzwGot, xyzwNum); |
1123 |
|
|
return 1; |
1124 |
|
|
} |
1125 |
|
|
xyzw = pld->xyzw + 4*xyzwGot; |
1126 |
|
|
if (3 != airParseStrF(xyzw, line, AIR_WHITESPACE, 3)) { |
1127 |
|
|
biffAddf(LIMN, "%s: couldn't parse 3 floats from \"%s\" " |
1128 |
|
|
"for vert %d (of %d)", |
1129 |
|
|
me, line, xyzwGot, xyzwNum); |
1130 |
|
|
return 1; |
1131 |
|
|
} |
1132 |
|
|
xyzw[3] = 1.0; |
1133 |
|
|
xyzwGot++; |
1134 |
|
|
} |
1135 |
|
|
|
1136 |
|
|
/* read face information */ |
1137 |
|
|
faceGot = 0; |
1138 |
|
|
while (faceGot < faceNum) { |
1139 |
|
|
unsigned int *indx, indxSingle[4], indxNum; |
1140 |
|
|
do { |
1141 |
|
|
lret = airOneLine(file, line, AIR_STRLEN_LARGE); |
1142 |
|
|
lineCount++; |
1143 |
|
|
} while (1 == lret); |
1144 |
|
|
if (!lret) { |
1145 |
|
|
biffAddf(LIMN, |
1146 |
|
|
"%s: (near line %d) hit EOF trying to read face %d (of %d)", |
1147 |
|
|
me, lineCount, faceGot, faceNum); |
1148 |
|
|
return 1; |
1149 |
|
|
} |
1150 |
|
|
if ('#' == line[0]) { |
1151 |
|
|
/* its some kind of comment, either LIMN BEGIN PART or otherwise */ |
1152 |
|
|
continue; |
1153 |
|
|
} |
1154 |
|
|
if (1 != sscanf(line, "%u", &indxNum)) { |
1155 |
|
|
biffAddf(LIMN, "%s: (near line %d) can't get first uint " |
1156 |
|
|
"(#verts) from \"%s\" for face %d (of %d)", |
1157 |
|
|
me, lineCount, line, faceGot, faceNum); |
1158 |
|
|
return 1; |
1159 |
|
|
} |
1160 |
|
|
if (3 != indxNum) { |
1161 |
|
|
biffAddf(LIMN, "%s: sorry, can only handle triangles (not %u verts)", |
1162 |
|
|
me, indxNum); |
1163 |
|
|
return 1; |
1164 |
|
|
} |
1165 |
|
|
if (indxNum+1 != airParseStrUI(indxSingle, line, |
1166 |
|
|
AIR_WHITESPACE, indxNum+1)) { |
1167 |
|
|
biffAddf(LIMN, "%s: (near line %d) couldn't parse %d uints from \"%s\" " |
1168 |
|
|
"for face %d (of %d)", |
1169 |
|
|
me, lineCount, indxNum+1, line, faceGot, faceNum); |
1170 |
|
|
return 1; |
1171 |
|
|
} |
1172 |
|
|
indx = pld->indx + 3*faceGot; |
1173 |
|
|
ELL_3V_SET(indx, indxSingle[1], indxSingle[2], indxSingle[3]); |
1174 |
|
|
/* for now ignoring the color information */ |
1175 |
|
|
faceGot++; |
1176 |
|
|
} |
1177 |
|
|
|
1178 |
|
|
/* set remaining info */ |
1179 |
|
|
pld->type[0] = limnPrimitiveTriangles; |
1180 |
|
|
pld->icnt[0] = 3*faceNum; |
1181 |
|
|
|
1182 |
|
|
return 0; |
1183 |
|
|
} |
1184 |
|
|
|
1185 |
|
|
int |
1186 |
|
|
limnPolyDataSave(const char *_fname, const limnPolyData *lpld) { |
1187 |
|
|
static const char me[]="limnPolyDataSave"; |
1188 |
|
|
char *fname; |
1189 |
|
|
FILE *file; |
1190 |
|
|
airArray *mop; |
1191 |
|
|
int ret; |
1192 |
|
|
|
1193 |
|
|
if (!(_fname && lpld)) { |
1194 |
|
|
biffAddf(LIMN, "%s: got NULL pointer", me); |
1195 |
|
|
return 1; |
1196 |
|
|
} |
1197 |
|
|
mop = airMopNew(); |
1198 |
|
|
|
1199 |
|
|
if (!( file = airFopen(_fname, stdout, "wb") )) { |
1200 |
|
|
biffAddf(LIMN, "%s: couldn't fopen(\"%s\",\"wb\"): %s", |
1201 |
|
|
me, _fname, strerror(errno)); |
1202 |
|
|
airMopError(mop); return 1; |
1203 |
|
|
} |
1204 |
|
|
airMopAdd(mop, file, (airMopper)airFclose, airMopAlways); |
1205 |
|
|
|
1206 |
|
|
fname = airToLower(airStrdup(_fname)); |
1207 |
|
|
airMopAdd(mop, fname, (airMopper)airFree, airMopAlways); |
1208 |
|
|
if (airEndsWith(fname, ".vtk")) { |
1209 |
|
|
ret = limnPolyDataWriteVTK(file, lpld); |
1210 |
|
|
} else if (airEndsWith(fname, ".iv")) { |
1211 |
|
|
ret = limnPolyDataWriteIV(file, lpld); |
1212 |
|
|
} else { |
1213 |
|
|
if (strcmp(_fname, "-") && !airEndsWith(fname, ".lmpd")) { |
1214 |
|
|
fprintf(stderr, "%s: WARNING: unknown or no suffix on \"%s\"; " |
1215 |
|
|
"using LMPD format", me, _fname); |
1216 |
|
|
} |
1217 |
|
|
ret = limnPolyDataWriteLMPD(file, lpld); |
1218 |
|
|
} |
1219 |
|
|
if (ret) { |
1220 |
|
|
biffAddf(LIMN, "%s: trouble", me); |
1221 |
|
|
airMopError(mop); return 1; |
1222 |
|
|
} |
1223 |
|
|
|
1224 |
|
|
airMopOkay(mop); |
1225 |
|
|
return 0; |
1226 |
|
|
} |