GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: src/limn/obj.c Lines: 46 176 26.1 %
Date: 2017-05-26 Branches: 4 44 9.1 %

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
/* restricted to this file now since here is the only place its needed */
28
typedef union {
29
  limnVertex **vert;
30
  limnEdge **edge;
31
  limnFace **face;
32
  limnLook **look;
33
  limnPart ***partp;
34
  void **v;
35
} limnPtrPtrUnion;
36
37
int
38
limnObjectLookAdd(limnObject *obj) {
39
  int lookIdx;
40
  limnLook *look;
41
42
2
  lookIdx = airArrayLenIncr(obj->lookArr, 1);
43
1
  look = &(obj->look[lookIdx]);
44
1
  ELL_4V_SET(look->rgba, 1, 1, 1, 1);
45
1
  ELL_3V_SET(look->kads, 0.0, 1.0, 0.0);
46
1
  look->spow = 50;
47
1
  return lookIdx;
48
}
49
50
51
limnObject *
52
limnObjectNew(int incr, int doEdges) {
53
  limnObject *obj;
54
  limnPtrPtrUnion lppu;
55
56
2
  obj = AIR_CALLOC(1, limnObject);
57
1
  obj->vert = NULL;
58
1
  obj->edge = NULL;
59
1
  obj->face = NULL;
60
1
  obj->faceSort = NULL;
61
1
  obj->part = NULL;
62
1
  obj->partPool = NULL;
63
1
  obj->look = NULL;
64
65
  /* create all various airArrays */
66
2
  obj->vertArr = airArrayNew((lppu.vert = &(obj->vert), lppu.v),
67
1
                             &(obj->vertNum),
68
                             sizeof(limnVertex), incr);
69
2
  obj->edgeArr = airArrayNew((lppu.edge = &(obj->edge), lppu.v),
70
1
                             &(obj->edgeNum),
71
                             sizeof(limnEdge), incr);
72
2
  obj->faceArr = airArrayNew((lppu.face = &(obj->face), lppu.v),
73
1
                             &(obj->faceNum),
74
                             sizeof(limnFace), incr);
75
2
  obj->partArr = airArrayNew((lppu.partp = &(obj->part), lppu.v),
76
1
                             &(obj->partNum),
77
                             sizeof(limnPart*), incr);
78
2
  obj->partPoolArr = airArrayNew((lppu.partp = &(obj->partPool), lppu.v),
79
1
                                 &(obj->partPoolNum),
80
                                 sizeof(limnPart*), incr);
81
2
  obj->lookArr = airArrayNew((lppu.look = &(obj->look), lppu.v),
82
1
                             &(obj->lookNum),
83
                             sizeof(limnLook), incr);
84
85
  /* create (default) look 0 */
86
1
  limnObjectLookAdd(obj);
87
88
1
  obj->vertSpace = limnSpaceUnknown;
89
1
  obj->setVertexRGBAFromLook = AIR_FALSE;
90
1
  obj->doEdges = doEdges;
91
1
  obj->incr = incr;
92
93
1
  return obj;
94
}
95
96
limnPart *
97
_limnObjectPartNew(int incr) {
98
  limnPart *part;
99
  airPtrPtrUnion appu;
100
101
  part = AIR_CALLOC(1, limnPart);
102
  if (part) {
103
    part->vertIdx = NULL;
104
    part->edgeIdx = NULL;
105
    part->faceIdx = NULL;
106
    part->vertIdxArr = airArrayNew((appu.ui = &(part->vertIdx), appu.v),
107
                                   &(part->vertIdxNum),
108
                                   sizeof(int), incr);
109
    part->edgeIdxArr = airArrayNew((appu.ui = &(part->edgeIdx), appu.v),
110
                                   &(part->edgeIdxNum),
111
                                   sizeof(int), incr);
112
    part->faceIdxArr = airArrayNew((appu.ui = &(part->faceIdx), appu.v),
113
                                   &(part->faceIdxNum),
114
                                   sizeof(int), incr);
115
  }
116
  return part;
117
}
118
119
limnPart *
120
_limnObjectPartNix(limnPart *part) {
121
122
  if (part) {
123
    airArrayNuke(part->vertIdxArr);
124
    airArrayNuke(part->edgeIdxArr);
125
    airArrayNuke(part->faceIdxArr);
126
    airFree(part);
127
  }
128
  return NULL;
129
}
130
131
void
132
_limnObjectFaceEmpty(limnFace *face) {
133
134
  if (face) {
135
    airFree(face->vertIdx);
136
    airFree(face->edgeIdx);
137
  }
138
  return;
139
}
140
141
limnObject *
142
limnObjectNix(limnObject *obj) {
143
  unsigned int partIdx, faceIdx;
144
145
2
  if (obj) {
146
2
    for (partIdx=0; partIdx<obj->partNum; partIdx++) {
147
      _limnObjectPartNix(obj->part[partIdx]);
148
    }
149
1
    airArrayNuke(obj->partArr);
150
2
    for (partIdx=0; partIdx<obj->partPoolNum; partIdx++) {
151
      _limnObjectPartNix(obj->partPool[partIdx]);
152
    }
153
1
    airArrayNuke(obj->partPoolArr);
154
2
    for (faceIdx=0; faceIdx<obj->faceNum; faceIdx++) {
155
      _limnObjectFaceEmpty(obj->face + faceIdx);
156
    }
157
1
    airArrayNuke(obj->faceArr);
158
1
    airArrayNuke(obj->vertArr);
159
1
    airArrayNuke(obj->edgeArr);
160
1
    airFree(obj->faceSort);
161
1
    airArrayNuke(obj->lookArr);
162
1
    airFree(obj);
163
1
  }
164
1
  return NULL;
165
}
166
167
void
168
limnObjectEmpty(limnObject *obj) {
169
  unsigned int partIdx, faceIdx;
170
171
  for (partIdx=0; partIdx<obj->partNum; partIdx++) {
172
    _limnObjectPartNix(obj->part[partIdx]);
173
  }
174
  airArrayLenSet(obj->partArr, 0);
175
  for (partIdx=0; partIdx<obj->partPoolNum; partIdx++) {
176
    _limnObjectPartNix(obj->partPool[partIdx]);
177
  }
178
  airArrayLenSet(obj->partPoolArr, 0);
179
  for (faceIdx=0; faceIdx<obj->faceNum; faceIdx++) {
180
    _limnObjectFaceEmpty(obj->face + faceIdx);
181
  }
182
  airArrayLenSet(obj->faceArr, 0);
183
  airArrayLenSet(obj->vertArr, 0);
184
  airArrayLenSet(obj->edgeArr, 0);
185
  airFree(obj->faceSort);
186
  /* leaves (default) look 0 */
187
  airArrayLenSet(obj->lookArr, 1);
188
189
  /* don't touch state flags */
190
191
  return;
192
}
193
194
/*
195
******** limnObjectPreSet
196
**
197
** an attempt at pre-allocating everything that will be needed in a
198
** limnObject, so that there will be no calloc/memcpy overhead associated
199
** with growing any of the airArrays inside
200
*/
201
int
202
limnObjectPreSet(limnObject *obj, unsigned int partNum,
203
                 unsigned int lookNum, unsigned int vertPerPart,
204
                 unsigned int edgePerPart, unsigned int facePerPart) {
205
  limnPart *part;
206
  unsigned int partIdx;
207
208
  limnObjectEmpty(obj);
209
  airArrayLenPreSet(obj->vertArr, partNum*vertPerPart);
210
  airArrayLenPreSet(obj->edgeArr, partNum*edgePerPart);
211
  airArrayLenPreSet(obj->faceArr, partNum*facePerPart);
212
  airArrayLenPreSet(obj->lookArr, lookNum);
213
  airArrayLenPreSet(obj->partArr, partNum);
214
215
  airArrayLenSet(obj->partPoolArr, partNum);
216
  for (partIdx=0; partIdx<partNum; partIdx++) {
217
    part = obj->partPool[partIdx] = _limnObjectPartNew(obj->incr);
218
    airArrayLenPreSet(part->vertIdxArr, vertPerPart);
219
    airArrayLenPreSet(part->edgeIdxArr, edgePerPart);
220
    airArrayLenPreSet(part->faceIdxArr, facePerPart);
221
  }
222
223
  return 0;
224
}
225
226
int
227
limnObjectPartAdd(limnObject *obj) {
228
  unsigned int partIdx;
229
  limnPart *part;
230
231
  partIdx = airArrayLenIncr(obj->partArr, 1);
232
  if (obj->partPoolNum > 0) {
233
    part = obj->part[partIdx] = obj->partPool[obj->partPoolNum - 1];
234
    airArrayLenIncr(obj->partPoolArr, -1);
235
    airArrayLenSet(part->vertIdxArr, 0);
236
    airArrayLenSet(part->edgeIdxArr, 0);
237
    airArrayLenSet(part->faceIdxArr, 0);
238
  } else {
239
    /* there are no available parts in the pool */
240
    part = obj->part[partIdx] = _limnObjectPartNew(obj->incr);
241
  }
242
  part->lookIdx = 0;
243
  part->depth = AIR_NAN;
244
  return partIdx;
245
}
246
247
int
248
limnObjectVertexNumPreSet(limnObject *obj, unsigned int partIdx,
249
                          unsigned int vertNum) {
250
  limnPart *part;
251
252
  part = obj->part[partIdx];
253
  airArrayLenPreSet(obj->vertArr, vertNum);
254
  airArrayLenPreSet(part->vertIdxArr, vertNum);
255
  return 0;
256
}
257
258
int
259
limnObjectVertexAdd(limnObject *obj, unsigned int partIdx,
260
                    float x, float y, float z) {
261
  limnPart *part;
262
  limnVertex *vert;
263
  int vertIdx, vertIdxIdx;
264
265
  part = obj->part[partIdx];
266
  vertIdx = airArrayLenIncr(obj->vertArr, 1);
267
  vert = obj->vert + vertIdx;
268
  vertIdxIdx = airArrayLenIncr(part->vertIdxArr, 1);
269
  part->vertIdx[vertIdxIdx] = vertIdx;
270
  ELL_4V_SET(vert->world, x, y, z, 1);
271
  ELL_4V_SET(vert->coord, AIR_NAN, AIR_NAN, AIR_NAN, AIR_NAN);
272
  /* HEY: this is kind of lame: this information is set in
273
     a rather sneaky way, and the setVertexRGBAFromLook is
274
     pretty clearly a hack */
275
  if (obj->setVertexRGBAFromLook) {
276
    ELL_4V_COPY(vert->rgba, obj->look[part->lookIdx].rgba);
277
  } else {
278
    ELL_4V_SET(vert->rgba, 1, 1, 1, 1);
279
  }
280
  /* ELL_3V_SET(vert->view, AIR_NAN, AIR_NAN, AIR_NAN); */
281
  /* ELL_3V_SET(vert->screen, AIR_NAN, AIR_NAN, AIR_NAN); */
282
  ELL_3V_SET(vert->worldNormal, AIR_NAN, AIR_NAN, AIR_NAN);
283
284
  return vertIdx;
285
}
286
287
int
288
limnObjectEdgeAdd(limnObject *obj, unsigned int partIdx,
289
                  unsigned int lookIdx, unsigned int faceIdx,
290
                  unsigned int vertIdx0, unsigned int vertIdx1) {
291
  int tmp, edgeIdx=-42;
292
  unsigned int edgeIdxIdx;
293
  limnEdge *edge=NULL;
294
  limnPart *part;
295
296
  part = obj->part[partIdx];
297
  if (vertIdx0 > vertIdx1) {
298
    ELL_SWAP2(vertIdx0, vertIdx1, tmp);
299
  }
300
301
  /* do a linear search through this part's existing edges */
302
  for (edgeIdxIdx=0; edgeIdxIdx<part->edgeIdxNum; edgeIdxIdx++) {
303
    edgeIdx = part->edgeIdx[edgeIdxIdx];
304
    edge = obj->edge + edgeIdx;
305
    if (edge->vertIdx[0] == vertIdx0
306
        && edge->vertIdx[1] == vertIdx1) {
307
      break;
308
    }
309
  }
310
  if (edgeIdxIdx == part->edgeIdxNum) {
311
    /* edge not found, add it */
312
    edgeIdx = airArrayLenIncr(obj->edgeArr, 1);
313
    edge = obj->edge + edgeIdx;
314
    edgeIdxIdx = airArrayLenIncr(part->edgeIdxArr, 1);
315
    part->edgeIdx[edgeIdxIdx] = edgeIdx;
316
    edge->vertIdx[0] = vertIdx0;
317
    edge->vertIdx[1] = vertIdx1;
318
    edge->faceIdx[0] = faceIdx;
319
    edge->faceIdx[1] = -1;
320
    edge->lookIdx = lookIdx;
321
    edge->partIdx = partIdx;
322
    edge->type = limnEdgeTypeUnknown;
323
    edge->once = AIR_FALSE;
324
  } else {
325
    /* edge already exists; "edge", "edgeIdx", and "edgeIdxIdx" are all set */
326
    edge->faceIdx[1] = faceIdx;
327
  }
328
329
  return edgeIdx;
330
}
331
332
int
333
limnObjectFaceNumPreSet(limnObject *obj, unsigned int partIdx,
334
                        unsigned int faceNum) {
335
  limnPart *part;
336
337
  part = obj->part[partIdx];
338
  airArrayLenPreSet(obj->faceArr, faceNum);
339
  airArrayLenPreSet(part->faceIdxArr, faceNum);
340
  return 0;
341
}
342
343
int
344
limnObjectFaceAdd(limnObject *obj, unsigned int partIdx,
345
                  unsigned int lookIdx, unsigned int sideNum,
346
                  unsigned int *vertIdx) {
347
  limnFace *face;
348
  limnPart *part;
349
  unsigned int faceIdx, faceIdxIdx, sideIdx;
350
351
  part = obj->part[partIdx];
352
  faceIdx = airArrayLenIncr(obj->faceArr, 1);
353
  face = obj->face + faceIdx;
354
  faceIdxIdx = airArrayLenIncr(part->faceIdxArr, 1);
355
  part->faceIdx[faceIdxIdx] = faceIdx;
356
357
  face->vertIdx = AIR_CALLOC(sideNum, unsigned int);
358
  face->sideNum = sideNum;
359
  if (obj->doEdges) {
360
    face->edgeIdx = AIR_CALLOC(sideNum, unsigned int);
361
  }
362
  for (sideIdx=0; sideIdx<sideNum; sideIdx++) {
363
    face->vertIdx[sideIdx] = vertIdx[sideIdx];
364
    if (obj->doEdges) {
365
      face->edgeIdx[sideIdx] =
366
        limnObjectEdgeAdd(obj, partIdx, 0, faceIdx,
367
                          vertIdx[sideIdx],
368
                          vertIdx[AIR_MOD((int)sideIdx+1, (int)sideNum)]);
369
    }
370
  }
371
  ELL_3V_SET(face->worldNormal, AIR_NAN, AIR_NAN, AIR_NAN);
372
  ELL_3V_SET(face->screenNormal, AIR_NAN, AIR_NAN, AIR_NAN);
373
  /* HEY: its potentially confusing that obj->setVertexRGBAFromLook only
374
     has an effect with whole parts, and not individual faces */
375
  face->lookIdx = lookIdx;
376
  face->partIdx = partIdx;
377
  face->visible = AIR_FALSE;
378
  face->depth = AIR_NAN;
379
380
  return faceIdx;
381
}
382