File: | src/limn/renderLimn.c |
Location: | line 369, column 5 |
Description: | Value stored to 'part' is never read |
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 | limnObjectRender(limnObject *obj, limnCamera *cam, limnWindow *win) { |
29 | static const char me[]="limnObjectRender"; |
30 | int E; |
31 | |
32 | E = 0; |
33 | if (!E) E |= limnCameraUpdate(cam); |
34 | /* |
35 | fprintf(stderr, "%s: true up = %g %g %g\n", me, |
36 | -cam->V[0], -cam->V[1], -cam->V[2]); |
37 | fprintf(stderr, "%s: true right = %g %g %g\n", me, |
38 | cam->U[0], cam->U[1], cam->U[2]); |
39 | */ |
40 | if (!E) E |= limnObjectWorldHomog(obj); |
41 | if (!E) E |= limnObjectFaceNormals(obj, limnSpaceWorld); |
42 | if (!E) E |= limnObjectSpaceTransform(obj, cam, win, limnSpaceView); |
43 | if (!E) E |= limnObjectSpaceTransform(obj, cam, win, limnSpaceScreen); |
44 | if (!E) E |= limnObjectFaceNormals(obj, limnSpaceScreen); |
45 | if (!E) E |= limnObjectSpaceTransform(obj, cam, win, limnSpaceDevice); |
46 | if (E) { |
47 | biffAddf(LIMNlimnBiffKey, "%s: trouble", me); |
48 | return 1; |
49 | } |
50 | return 0; |
51 | } |
52 | |
53 | void |
54 | _limnPSPreamble(limnObject *obj, limnCamera *cam, limnWindow *win) { |
55 | |
56 | AIR_UNUSED(obj)(void)(obj); |
57 | AIR_UNUSED(cam)(void)(cam); |
58 | fprintf(win->file, "%%!PS-Adobe-2.0 EPSF-2.0\n"); |
59 | fprintf(win->file, "%%%%Creator: limn\n"); |
60 | fprintf(win->file, "%%%%Pages: 1\n"); |
61 | fprintf(win->file, "%%%%BoundingBox: %d %d %d %d\n", |
62 | (int)(win->bbox[0]), |
63 | (int)(win->bbox[1]), |
64 | (int)(win->bbox[2]), |
65 | (int)(win->bbox[3])); |
66 | fprintf(win->file, "%%%%EndComments\n"); |
67 | fprintf(win->file, "%%%%EndProlog\n"); |
68 | fprintf(win->file, "%%%%Page: 1 1\n"); |
69 | fprintf(win->file, "gsave\n"); |
70 | fprintf(win->file, "%g %g moveto\n", win->bbox[0], win->bbox[1]); |
71 | fprintf(win->file, "%g %g lineto\n", win->bbox[2], win->bbox[1]); |
72 | fprintf(win->file, "%g %g lineto\n", win->bbox[2], win->bbox[3]); |
73 | fprintf(win->file, "%g %g lineto\n", win->bbox[0], win->bbox[3]); |
74 | fprintf(win->file, "closepath\n"); |
75 | if (!win->ps.noBackground) { |
76 | fprintf(win->file, "gsave %g %g %g setrgbcolor fill grestore\n", |
77 | win->ps.bg[0], win->ps.bg[1], win->ps.bg[2]); |
78 | } |
79 | fprintf(win->file, "clip\n"); |
80 | fprintf(win->file, "gsave newpath\n"); |
81 | fprintf(win->file, "1 setlinejoin\n"); |
82 | fprintf(win->file, "1 setlinecap\n"); |
83 | fprintf(win->file, "/M {moveto} bind def\n"); |
84 | fprintf(win->file, "/L {lineto} bind def\n"); |
85 | fprintf(win->file, "/W {setlinewidth} bind def\n"); |
86 | fprintf(win->file, "/F {fill} bind def\n"); |
87 | fprintf(win->file, "/S {stroke} bind def\n"); |
88 | fprintf(win->file, "/CP {closepath} bind def\n"); |
89 | fprintf(win->file, "/RGB {setrgbcolor} bind def\n"); |
90 | fprintf(win->file, "/Gr {setgray} bind def\n"); |
91 | fprintf(win->file, "\n"); |
92 | } |
93 | |
94 | void |
95 | _limnPSEpilogue(limnObject *obj, limnCamera *cam, limnWindow *win) { |
96 | |
97 | AIR_UNUSED(obj)(void)(obj); |
98 | AIR_UNUSED(cam)(void)(cam); |
99 | fprintf(win->file, "grestore\n"); |
100 | fprintf(win->file, "grestore\n"); |
101 | if (win->ps.showpage) { |
102 | fprintf(win->file, "showpage\n"); |
103 | } |
104 | fprintf(win->file, "%%%%Trailer\n"); |
105 | } |
106 | |
107 | void |
108 | _limnPSDrawFace(limnObject *obj, limnFace *face, |
109 | limnCamera *cam, Nrrd *nmap, limnWindow *win) { |
110 | /* static const char me[]="_limnPSDrawFace"; */ |
111 | unsigned int vii; |
112 | limnVertex *vert; |
113 | limnLook *look; |
114 | int qn; |
115 | float *map, R, G, B; |
116 | |
117 | AIR_UNUSED(cam)(void)(cam); |
118 | look = obj->look + face->lookIdx; |
119 | for (vii=0; vii<face->sideNum; vii++) { |
120 | vert = obj->vert + face->vertIdx[vii]; |
121 | fprintf(win->file, "%g %g %s\n", |
122 | vert->coord[0], vert->coord[1], vii ? "L" : "M"); |
123 | } |
124 | R = look->kads[0]*look->rgba[0]; |
125 | G = look->kads[0]*look->rgba[1]; |
126 | B = look->kads[0]*look->rgba[2]; |
127 | if (nmap) { |
128 | qn = limnVtoQN_f[limnQN16octa](face->worldNormal); |
129 | map = (float *)nmap->data; |
130 | R += look->kads[1]*look->rgba[0]*map[0 + 3*qn]; |
131 | G += look->kads[1]*look->rgba[1]*map[1 + 3*qn]; |
132 | B += look->kads[1]*look->rgba[2]*map[2 + 3*qn]; |
133 | } else { |
134 | R += look->kads[1]*look->rgba[0]; |
135 | G += look->kads[1]*look->rgba[1]; |
136 | B += look->kads[1]*look->rgba[2]; |
137 | } |
138 | /* HEY: not evaluating phong specular for now */ |
139 | R = AIR_CLAMP(0, R, 1)((R) < (0) ? (0) : ((R) > (1) ? (1) : (R))); |
140 | G = AIR_CLAMP(0, G, 1)((G) < (0) ? (0) : ((G) > (1) ? (1) : (G))); |
141 | B = AIR_CLAMP(0, B, 1)((B) < (0) ? (0) : ((B) > (1) ? (1) : (B))); |
142 | if (0 && R == G && G == B) { |
143 | /* As of Sat Mar 1 23:06:14 CST 2014 some version of ghostscript |
144 | and/or imagemagick will assign (when rasterizing) different |
145 | colors for RGB color (g,g,g) and graylevel g, which caused |
146 | strange appearance bugs that were hard to track down. Even if |
147 | there's a way of preventing this from happening with the right |
148 | incantation in the EPS header, for now it is simpler to forego |
149 | the small economy implemented here */ |
150 | fprintf(win->file, "CP %g Gr F\n", R); |
151 | } |
152 | else { |
153 | fprintf(win->file, "CP %g %g %g RGB F\n", R, G, B); |
154 | } |
155 | } |
156 | |
157 | void |
158 | _limnPSDrawEdge(limnObject *obj, limnEdge *edge, |
159 | limnCamera *cam, limnWindow *win) { |
160 | limnVertex *vert0, *vert1; |
161 | float R, G, B; |
162 | |
163 | AIR_UNUSED(cam)(void)(cam); |
164 | if (win->ps.lineWidth[edge->type]) { |
165 | vert0 = obj->vert + edge->vertIdx[0]; |
166 | vert1 = obj->vert + edge->vertIdx[1]; |
167 | fprintf(win->file, "%g %g M ", vert0->coord[0], vert0->coord[1]); |
168 | fprintf(win->file, "%g %g L ", vert1->coord[0], vert1->coord[1]); |
169 | fprintf(win->file, "%g W ", win->ps.lineWidth[edge->type]); |
170 | R = win->ps.edgeColor[0]; |
171 | G = win->ps.edgeColor[1]; |
172 | B = win->ps.edgeColor[2]; |
173 | if (R == G && G == B) { |
174 | fprintf(win->file, "%g Gr S\n", R); |
175 | } else { |
176 | fprintf(win->file, "%g %g %g RGB S\n", R, G, B); |
177 | } |
178 | } |
179 | } |
180 | |
181 | /* |
182 | ******** limnObjectPSDraw |
183 | ** |
184 | ** draws a "rendered" limn object to postscript. |
185 | ** limnObjectRender MUST be called first. |
186 | ** |
187 | ** The current (feeble) justification for using an environment map is |
188 | ** that its an expressive way of shading things based on surface |
189 | ** normal, in a context where, if flat shading is all you have, |
190 | ** correct specular lighting is not possible |
191 | */ |
192 | int |
193 | limnObjectPSDraw(limnObject *obj, limnCamera *cam, |
194 | Nrrd *nmap, limnWindow *win) { |
195 | static const char me[]="limnObjectPSDraw"; |
196 | int inside; |
197 | float angle; |
198 | limnFace *face, *face0, *face1; unsigned int fii; |
199 | limnEdge *edge; unsigned int eii; |
200 | limnPart *part; unsigned int partIdx; |
201 | limnVertex *vert; unsigned int vii; |
202 | |
203 | if (limnSpaceDevice != obj->vertSpace) { |
204 | biffAddf(LIMNlimnBiffKey, "%s: object's verts in %s (not %s) space", me, |
205 | airEnumStr(limnSpace, obj->vertSpace), |
206 | airEnumStr(limnSpace, limnSpaceDevice)); |
207 | return 1; |
208 | } |
209 | if (nmap) { |
210 | if (limnEnvMapCheck(nmap)) { |
211 | biffAddf(LIMNlimnBiffKey, "%s: trouble", me); |
212 | return 1; |
213 | } |
214 | } |
215 | |
216 | limnObjectDepthSortParts(obj); |
217 | |
218 | _limnPSPreamble(obj, cam, win); |
219 | |
220 | for (partIdx=0; partIdx<obj->partNum; partIdx++) { |
221 | part = obj->part[partIdx]; |
222 | |
223 | /* only draw the parts that are inside the field of view */ |
224 | inside = 0; |
225 | for (vii=0; vii<part->vertIdxNum; vii++) { |
226 | vert = obj->vert + part->vertIdx[vii]; |
227 | inside |= (AIR_IN_CL(win->bbox[0], vert->coord[0], win->bbox[2])((win->bbox[0]) <= (vert->coord[0]) && (vert ->coord[0]) <= (win->bbox[2])) && |
228 | AIR_IN_CL(win->bbox[1], vert->coord[1], win->bbox[3])((win->bbox[1]) <= (vert->coord[1]) && (vert ->coord[1]) <= (win->bbox[3]))); |
229 | if (inside) { |
230 | /* at least vertex is in, we know we can't skip this part */ |
231 | break; |
232 | } |
233 | } |
234 | if (!inside) { |
235 | /* none of the vertices were in, we can skip this part */ |
236 | continue; |
237 | } |
238 | |
239 | /* draw the part */ |
240 | if (1 == part->edgeIdxNum) { |
241 | /* this part is just one lone edge */ |
242 | /* HEY: this is a mess */ |
243 | /* |
244 | e = &(obj->e[r->eBase]); |
245 | widthTmp = win->ps.lineWidth[e->type]; |
246 | fprintf(win->file, "%g setgray\n", 1 - win->ps.bg[0]); |
247 | win->ps.edgeWidth[e->type] = 8; |
248 | _limnPSDrawEdge(obj, r, e, cam, win); |
249 | fprintf(win->file, "%g %g %g RGB\n", |
250 | r->rgba[0], r->rgba[1], r->rgba[2]); |
251 | win->ps.edgeWidth[e->visible] = 4; |
252 | _limnPSDrawEdge(obj, r, e, cam, win); |
253 | win->ps.edgeWidth[e->visible] = widthTmp; |
254 | */ |
255 | } else { |
256 | /* this part is either a lone face or a solid: |
257 | draw the front-facing, shaded faces */ |
258 | for (fii=0; fii<part->faceIdxNum; fii++) { |
259 | face = obj->face + part->faceIdx[fii]; |
260 | /* The consequence of having a left-handed frame is that world-space |
261 | CC-wise vertex traversal becomes C-wise screen-space traversal, so |
262 | all the normals are backwards of what we want */ |
263 | face->visible = (cam->rightHanded |
264 | ? face->screenNormal[2] < 0 |
265 | : face->screenNormal[2] > 0); |
266 | if (face->sideNum == part->vertIdxNum && !face->visible) { |
267 | /* lone faces are always visible */ |
268 | face->visible = AIR_TRUE1; |
269 | ELL_3V_SCALE(face->worldNormal, -1, face->worldNormal)((face->worldNormal)[0] = (-1)*(face->worldNormal)[0], ( face->worldNormal)[1] = (-1)*(face->worldNormal)[1], (face ->worldNormal)[2] = (-1)*(face->worldNormal)[2]); |
270 | } |
271 | if (!win->ps.wireFrame && face->visible) { |
272 | _limnPSDrawFace(obj, face, cam, nmap, win); |
273 | } |
274 | } |
275 | |
276 | /* draw ALL edges */ |
277 | for (eii=0; eii<part->edgeIdxNum; eii++) { |
278 | /* hack to change contour of particular object/glyph |
279 | if (24 == partIdx) { |
280 | win->ps.lineWidth[limnEdgeTypeContour] = 1.2; |
281 | } else { |
282 | win->ps.lineWidth[limnEdgeTypeContour] = 0.4; |
283 | } |
284 | */ |
285 | edge = obj->edge + part->edgeIdx[eii]; |
286 | face0 = obj->face + edge->faceIdx[0]; |
287 | face1 = (-1 == edge->faceIdx[1] |
288 | ? NULL((void*)0) |
289 | : obj->face + edge->faceIdx[1]); |
290 | if (!face1) { |
291 | edge->type = limnEdgeTypeBorder; |
292 | } else { |
293 | angle = AIR_CAST(float,((float)(180/3.14159265358979323846*acos(((face0->worldNormal )[0]*(face1->worldNormal)[0] + (face0->worldNormal)[1]* (face1->worldNormal)[1] + (face0->worldNormal)[2]*(face1 ->worldNormal)[2])))) |
294 | 180/AIR_PI*acos(ELL_3V_DOT(face0->worldNormal,((float)(180/3.14159265358979323846*acos(((face0->worldNormal )[0]*(face1->worldNormal)[0] + (face0->worldNormal)[1]* (face1->worldNormal)[1] + (face0->worldNormal)[2]*(face1 ->worldNormal)[2])))) |
295 | face1->worldNormal)))((float)(180/3.14159265358979323846*acos(((face0->worldNormal )[0]*(face1->worldNormal)[0] + (face0->worldNormal)[1]* (face1->worldNormal)[1] + (face0->worldNormal)[2]*(face1 ->worldNormal)[2])))); |
296 | if (face0->visible && face1->visible) { |
297 | edge->type = (angle > win->ps.creaseAngle |
298 | ? limnEdgeTypeFrontCrease |
299 | : limnEdgeTypeFrontFacet); |
300 | } else if (face0->visible ^ face1->visible) { |
301 | edge->type = limnEdgeTypeContour; |
302 | } else { |
303 | edge->type = (angle > win->ps.creaseAngle |
304 | ? limnEdgeTypeBackCrease |
305 | : limnEdgeTypeBackFacet); |
306 | } |
307 | } |
308 | _limnPSDrawEdge(obj, edge, cam, win); |
309 | } |
310 | } |
311 | } |
312 | |
313 | _limnPSEpilogue(obj, cam, win); |
314 | |
315 | return 0; |
316 | } |
317 | |
318 | /* |
319 | ******** limnObjectPSDrawConcave |
320 | ** |
321 | ** new version of the above, which works per-face instead of per-part, |
322 | ** thus better handling self-occlusions, but at the cost of not getting |
323 | ** contours near oblique faces correct... |
324 | */ |
325 | int |
326 | limnObjectPSDrawConcave(limnObject *obj, limnCamera *cam, |
327 | Nrrd *nmap, limnWindow *win) { |
328 | static const char me[]="limnObjectPSDrawConcave"; |
329 | float angle; |
330 | limnPart *part; |
331 | limnFace *face, *face0, *face1; unsigned int faceIdx; |
332 | limnEdge *edge; unsigned int edgeIdx, eii; |
333 | |
334 | if (limnSpaceDevice != obj->vertSpace) { |
335 | biffAddf(LIMNlimnBiffKey, "%s: object's verts in %s (not %s) space", me, |
336 | airEnumStr(limnSpace, obj->vertSpace), |
337 | airEnumStr(limnSpace, limnSpaceDevice)); |
338 | return 1; |
339 | } |
340 | if (nmap) { |
341 | if (limnEnvMapCheck(nmap)) { |
342 | biffAddf(LIMNlimnBiffKey, "%s: trouble", me); |
343 | return 1; |
344 | } |
345 | } |
346 | |
347 | limnObjectDepthSortFaces(obj); |
348 | |
349 | _limnPSPreamble(obj, cam, win); |
350 | |
351 | /* set every face's visibility */ |
352 | for (faceIdx=0; faceIdx<obj->faceNum; faceIdx++) { |
353 | face = obj->face + faceIdx; |
354 | part = obj->part[face->partIdx]; |
355 | face->visible = (cam->rightHanded |
356 | ? face->screenNormal[2] < 0 |
357 | : face->screenNormal[2] > 0); |
358 | if (face->sideNum == part->vertIdxNum && !face->visible) { |
359 | /* lone faces are always visible */ |
360 | face->visible = AIR_TRUE1; |
361 | ELL_3V_SCALE(face->worldNormal, -1, face->worldNormal)((face->worldNormal)[0] = (-1)*(face->worldNormal)[0], ( face->worldNormal)[1] = (-1)*(face->worldNormal)[1], (face ->worldNormal)[2] = (-1)*(face->worldNormal)[2]); |
362 | } |
363 | } |
364 | |
365 | /* categorize all edges by traversing edge array, and looking |
366 | at each of their two faces */ |
367 | for (edgeIdx=0; edgeIdx<obj->edgeNum; edgeIdx++) { |
368 | edge = obj->edge + edgeIdx; |
369 | part = obj->part[edge->partIdx]; |
Value stored to 'part' is never read | |
370 | face0 = obj->face + edge->faceIdx[0]; |
371 | face1 = (-1 == edge->faceIdx[1] |
372 | ? NULL((void*)0) |
373 | : obj->face + edge->faceIdx[1]); |
374 | if (!face1) { |
375 | edge->type = limnEdgeTypeBorder; |
376 | } else { |
377 | angle = AIR_CAST(float, 180/AIR_PI*acos(ELL_3V_DOT(face0->worldNormal,((float)(180/3.14159265358979323846*acos(((face0->worldNormal )[0]*(face1->worldNormal)[0] + (face0->worldNormal)[1]* (face1->worldNormal)[1] + (face0->worldNormal)[2]*(face1 ->worldNormal)[2])))) |
378 | face1->worldNormal)))((float)(180/3.14159265358979323846*acos(((face0->worldNormal )[0]*(face1->worldNormal)[0] + (face0->worldNormal)[1]* (face1->worldNormal)[1] + (face0->worldNormal)[2]*(face1 ->worldNormal)[2])))); |
379 | if (face0->visible && face1->visible) { |
380 | edge->type = (angle > win->ps.creaseAngle |
381 | ? limnEdgeTypeFrontCrease |
382 | : limnEdgeTypeFrontFacet); |
383 | } else if (face0->visible ^ face1->visible) { |
384 | edge->type = limnEdgeTypeContour; |
385 | } else { |
386 | edge->type = (angle > win->ps.creaseAngle |
387 | ? limnEdgeTypeBackCrease |
388 | : limnEdgeTypeBackFacet); |
389 | } |
390 | } |
391 | } |
392 | |
393 | /* draw front-faces and their edges |
394 | (contours, front crease, front non-crease) */ |
395 | for (faceIdx=0; faceIdx<obj->faceNum; faceIdx++) { |
396 | face = obj->faceSort[faceIdx]; |
397 | part = obj->part[face->partIdx]; |
398 | if (!face->visible) { |
399 | continue; |
400 | } |
401 | if (!win->ps.wireFrame) { |
402 | _limnPSDrawFace(obj, face, cam, nmap, win); |
403 | } |
404 | /* draw those edges around the face that won't be seen again by |
405 | future faces in the depth-first traversal */ |
406 | for (eii=0; eii<face->sideNum; eii++) { |
407 | edge = obj->edge + face->edgeIdx[eii]; |
408 | if (limnEdgeTypeContour == edge->type) { |
409 | _limnPSDrawEdge(obj, edge, cam, win); |
410 | } else if (limnEdgeTypeFrontCrease == edge->type |
411 | || limnEdgeTypeFrontFacet == edge->type) { |
412 | if (edge->once) { |
413 | /* its been seen once already, okay to draw */ |
414 | _limnPSDrawEdge(obj, edge, cam, win); |
415 | edge->once = AIR_FALSE0; |
416 | } else { |
417 | /* we're the first to see it, and we're not the last, don't draw */ |
418 | edge->once = AIR_TRUE1; |
419 | } |
420 | } |
421 | } |
422 | } |
423 | |
424 | _limnPSEpilogue(obj, cam, win); |
425 | |
426 | return 0; |
427 | } |