GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: src/limn/io.c Lines: 0 686 0.0 %
Date: 2017-05-26 Branches: 0 347 0.0 %

Line Branch Exec Source
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
}