ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/gen/genbox.c
Revision: 2.13
Committed: Thu Apr 15 23:51:04 2021 UTC (3 years ago) by greg
Content type: text/plain
Branch: MAIN
CVS Tags: rad5R4, HEAD
Changes since 2.12: +8 -2 lines
Log Message:
feat(genbox,robjutil): Added Radiance normal smoothing support to wfobj library

File Contents

# Content
1 #ifndef lint
2 static const char RCSid[] = "$Id: genbox.c,v 2.12 2021/04/09 18:52:57 greg Exp $";
3 #endif
4 /*
5 * genbox.c - generate a parallelepiped.
6 *
7 * 1/8/86
8 */
9
10 #include "rtio.h"
11 #include "rtmath.h"
12 #include "objutil.h"
13 #include <stdlib.h>
14
15
16 char *progname;
17
18 int verbose = 0;
19
20 char let[]="0123456789._ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
21
22 char *cmtype; /* ppd material type */
23
24 char *cname; /* ppd name */
25
26 double size[3]; /* ppd size */
27
28 int rounde = 0; /* round edges? (#segments = 2^rounde) */
29
30 double bevel = 0.0; /* bevel amount or round edge radius */
31
32 int rev = 0; /* boolean true for reversed normals */
33
34 Scene *obj = NULL; /* save as .OBJ scene if not NULL */
35
36 int vid[0100]; /* vertex ID's for .OBJ scene */
37
38
39 static int
40 overtex(int v) /* index a .OBJ vertex */
41 {
42 double vpos[3];
43 int i;
44
45 if (vid[v] >= 0) /* already have this vertex? */
46 return(vid[v]);
47 /* else create new ID */
48 for (i = 0; i < 3; i++)
49 if (v>>i & 010)
50 vpos[i] = (v>>i & 01)^rev ? size[i]-bevel : bevel;
51 else
52 vpos[i] = (v>>i & 01)^rev ? size[i] : 0.0;
53
54 return(vid[v] = addVertex(obj, vpos[0], vpos[1], vpos[2]));
55 }
56
57
58 static int
59 onormal(int vid1, int vid2, int vid3) /* index a .OBJ normal */
60 {
61 double *p1 = obj->vert[vid1].p;
62 double *p2 = obj->vert[vid2].p;
63 double *p3 = obj->vert[vid3].p;
64 FVECT sv1, sv2, nrm;
65
66 VSUB(sv1, p2, p1);
67 VSUB(sv2, p3, p2);
68 VCROSS(nrm, sv1, sv2);
69
70 return(addNormal(obj, nrm[0], nrm[1], nrm[2]));
71 }
72
73
74 static void
75 vertex(int v) /* print a Radiance vertex */
76 {
77 int i;
78
79 for (i = 0; i < 3; i++) {
80 if (v & 010)
81 printf("\t%18.12g", (v&01)^rev ? size[i]-bevel : bevel);
82 else
83 printf("\t%18.12g", (v&01)^rev ? size[i] : 0.0);
84 v >>= 1;
85 }
86 fputc('\n', stdout);
87 }
88
89
90 static void
91 side(int a, int b, int c, int d) /* generate a rectangular face */
92 {
93 if (obj != NULL) { /* working on .OBJ? */
94 VNDX quadv[4];
95 memset(quadv, 0xff, sizeof(quadv));
96 quadv[0][0] = overtex(a);
97 quadv[1][0] = overtex(b);
98 quadv[2][0] = overtex(c);
99 quadv[3][0] = overtex(d);
100 if (rounde) /* add normal if rounded */
101 quadv[0][2] = quadv[1][2] = quadv[2][2] = quadv[3][2]
102 = onormal(quadv[0][0], quadv[1][0], quadv[2][0]);
103 addFace(obj, quadv, 4);
104 return;
105 }
106 /* Radiance output */
107 printf("\n%s polygon %s.%c%c%c%c\n", cmtype, cname,
108 let[a], let[b], let[c], let[d]);
109 printf("0\n0\n12\n");
110 vertex(a);
111 vertex(b);
112 vertex(c);
113 vertex(d);
114 }
115
116
117 static void
118 corner(int a, int b, int c) /* generate a triangular face */
119 {
120 if (obj != NULL) { /* working on .OBJ? */
121 VNDX triv[3];
122 memset(triv, 0xff, sizeof(triv));
123 triv[0][0] = overtex(a);
124 triv[1][0] = overtex(b);
125 triv[2][0] = overtex(c);
126 addFace(obj, triv, 3);
127 return;
128 }
129 /* Radiance output */
130 printf("\n%s polygon %s.%c%c%c\n", cmtype, cname,
131 let[a], let[b], let[c]);
132 printf("0\n0\n9\n");
133 vertex(a);
134 vertex(b);
135 vertex(c);
136 }
137
138
139 static void
140 cylinder(int v0, int v1) /* generate a rounded edge */
141 {
142 if (obj != NULL) { /* segmenting for .OBJ? */
143 const int nsgn = 1 - 2*rev;
144 const int nseg = 1<<rounde;
145 const double astep = 0.5*PI/(double)nseg;
146 const int vid0 = overtex(v0);
147 const int vid1 = overtex(v1);
148 FVECT p0, p1;
149 FVECT axis[2], voff;
150 int previd[2];
151 int prenid;
152 VNDX quadv[4];
153 double coef[2];
154 int i, j;
155 /* need to copy b/c realloc */
156 VCOPY(p0, obj->vert[vid0].p);
157 VCOPY(p1, obj->vert[vid1].p);
158
159 memset(axis, 0, sizeof(axis));
160
161 switch ((v0 ^ v1) & 07) {
162 case 01: /* edge along X-axis */
163 axis[1][1] = bevel*(1. - 2.*(p1[1] < .5*size[1]));
164 axis[0][2] = bevel*(1. - 2.*(p1[2] < .5*size[2]));
165 break;
166 case 02: /* edge along Y-axis */
167 axis[0][0] = bevel*(1. - 2.*(p1[0] < .5*size[0]));
168 axis[1][2] = bevel*(1. - 2.*(p1[2] < .5*size[2]));
169 break;
170 case 04: /* edge along Z-axis */
171 axis[0][1] = bevel*(1. - 2.*(p1[1] < .5*size[1]));
172 axis[1][0] = bevel*(1. - 2.*(p1[0] < .5*size[0]));
173 break;
174 }
175 previd[0] = addVertex(obj, p0[0]+axis[0][0],
176 p0[1]+axis[0][1], p0[2]+axis[0][2]);
177 previd[1] = addVertex(obj, p1[0]+axis[0][0],
178 p1[1]+axis[0][1], p1[2]+axis[0][2]);
179 prenid = addNormal(obj, axis[0][0]*nsgn,
180 axis[0][1]*nsgn, axis[0][2]*nsgn);
181 for (i = 1; i <= nseg; i++) {
182 memset(quadv, 0xff, sizeof(quadv));
183 quadv[0][0] = previd[0];
184 quadv[1][0] = previd[1];
185 quadv[0][2] = quadv[1][2] = prenid;
186 coef[0] = cos(astep*i);
187 coef[1] = sin(astep*i);
188 for (j = 0; j < 3; j++)
189 voff[j] = coef[0]*axis[0][j] + coef[1]*axis[1][j];
190 previd[0] = quadv[3][0]
191 = addVertex(obj, p0[0]+voff[0],
192 p0[1]+voff[1], p0[2]+voff[2]);
193 previd[1] = quadv[2][0]
194 = addVertex(obj, p1[0]+voff[0],
195 p1[1]+voff[1], p1[2]+voff[2]);
196 prenid = quadv[2][2] = quadv[3][2]
197 = addNormal(obj, voff[0]*nsgn,
198 voff[1]*nsgn, voff[2]*nsgn);
199 addFace(obj, quadv, 4);
200 }
201 return;
202 }
203 /* Radiance output */
204 printf("\n%s cylinder %s.%c%c\n", cmtype, cname, let[v0], let[v1]);
205 printf("0\n0\n7\n");
206 vertex(v0);
207 vertex(v1);
208 printf("\t%18.12g\n", bevel);
209 }
210
211
212 static void /* recursive corner subdivision */
213 osubcorner(const FVECT orig, const FVECT c0, const FVECT c1, const FVECT c2, int lvl)
214 {
215 if (lvl-- <= 0) { /* reached terminal depth? */
216 const int nsgn = 1 - 2*rev;
217 FVECT vpos;
218 VNDX triv[3]; /* output smoothed triangle */
219 VSUM(vpos, orig, c0, bevel);
220 triv[0][0] = addVertex(obj, vpos[0], vpos[1], vpos[2]);
221 triv[0][2] = addNormal(obj, c0[0]*nsgn, c0[1]*nsgn, c0[2]*nsgn);
222 VSUM(vpos, orig, c1, bevel);
223 triv[1][0] = addVertex(obj, vpos[0], vpos[1], vpos[2]);
224 triv[1][2] = addNormal(obj, c1[0]*nsgn, c1[1]*nsgn, c1[2]*nsgn);
225 VSUM(vpos, orig, c2, bevel);
226 triv[2][0] = addVertex(obj, vpos[0], vpos[1], vpos[2]);
227 triv[2][2] = addNormal(obj, c2[0]*nsgn, c2[1]*nsgn, c2[2]*nsgn);
228 triv[0][1] = triv[1][1] = triv[2][1] = -1;
229 addFace(obj, triv, 3);
230 } else { /* else subdivide 4 subcorners */
231 FVECT m01, m12, m20;
232 VADD(m01, c0, c1); normalize(m01);
233 VADD(m12, c1, c2); normalize(m12);
234 VADD(m20, c2, c0); normalize(m20);
235 osubcorner(orig, c0, m01, m20, lvl);
236 osubcorner(orig, c1, m12, m01, lvl);
237 osubcorner(orig, c2, m20, m12, lvl);
238 osubcorner(orig, m01, m12, m20, lvl);
239 }
240 }
241
242
243 static void
244 sphere(int v0) /* generate a rounded corner */
245 {
246 if (obj != NULL) { /* segmenting for .OBJ? */
247 FVECT orig, cdir[3];
248 int i;
249 memset(cdir, 0, sizeof(cdir));
250 for (i = 0; i < 3; i++)
251 cdir[i][i] = 2*((v0>>i & 01)^rev) - 1;
252 switch (v0 & 07) {
253 case 0:
254 case 3:
255 case 5:
256 case 6:
257 VCOPY(orig, cdir[0]);
258 VCOPY(cdir[0], cdir[1]);
259 VCOPY(cdir[1], orig);
260 }
261 i = overtex(v0);
262 VCOPY(orig, obj->vert[i].p); /* realloc remedy */
263 osubcorner(orig, cdir[0], cdir[1], cdir[2], rounde);
264 return;
265 }
266 /* Radiance output */
267 printf("\n%s sphere %s.%c\n", cmtype, cname, let[v0]);
268 printf("0\n0\n4\n");
269 vertex(v0);
270 printf("\t%18.12g\n", bevel);
271 }
272
273
274 int
275 main(int argc, char *argv[])
276 {
277 int smooth = 0;
278 int nsegs = 1;
279 int objout = 0;
280 int i;
281
282 progname = argv[0];
283
284 if (argc < 6)
285 goto userr;
286
287 cmtype = argv[1];
288 cname = argv[2];
289 size[0] = atof(argv[3]);
290 size[1] = atof(argv[4]);
291 size[2] = atof(argv[5]);
292 if ((size[0] <= 0.0) | (size[1] <= 0.0) | (size[2] <= 0.0))
293 goto userr;
294
295 for (i = 6; i < argc; i++) {
296 if (argv[i][0] != '-')
297 goto userr;
298 switch (argv[i][1]) {
299 case 'o': /* requesting .OBJ output */
300 objout = 1;
301 break;
302 case 'i': /* invert surface normals */
303 rev = 1;
304 break;
305 case 's': /* normal smoothing? */
306 smooth = 1;
307 break;
308 case 'r': /* rounded edges/corners */
309 rounde = 1;
310 /* fall through */
311 case 'b': /* beveled edges */
312 bevel = atof(argv[++i]);
313 if (bevel <= 0.0)
314 goto userr;
315 break;
316 case 'n': /* #segments for rounding */
317 nsegs = atoi(argv[++i]);
318 if (nsegs <= 0)
319 goto userr;
320 break;
321 default:
322 goto userr;
323 }
324 }
325 if ((objout|rev) & (nsegs==1)) /* default to 32 segments/edge */
326 nsegs = 32;
327 if (rounde) { /* rounding edges/corners? */
328 --nsegs;
329 while ((nsegs >>= 1)) /* segmentation requested? */
330 ++rounde;
331 }
332 if (rounde > 1 || objout) { /* save as .OBJ scene? */
333 obj = newScene();
334 setMaterial(obj, cmtype);
335 setGroup(obj, cname);
336 memset(vid, 0xff, sizeof(vid));
337 }
338 fputs("# ", stdout); /* write command as comment */
339 printargs(argc, argv, stdout);
340
341 if (bevel > 0.0) { /* minor faces */
342 side(051, 055, 054, 050);
343 side(064, 066, 062, 060);
344 side(032, 033, 031, 030);
345 side(053, 052, 056, 057);
346 side(065, 061, 063, 067);
347 side(036, 034, 035, 037);
348 }
349 if (bevel > 0.0 && !rounde) { /* bevel faces */
350 side(031, 051, 050, 030);
351 side(060, 062, 032, 030);
352 side(050, 054, 064, 060);
353 side(034, 036, 066, 064);
354 side(037, 057, 056, 036);
355 side(052, 062, 066, 056);
356 side(052, 053, 033, 032);
357 side(057, 067, 063, 053);
358 side(061, 031, 033, 063);
359 side(065, 067, 037, 035);
360 side(055, 051, 061, 065);
361 side(034, 054, 055, 035);
362 /* bevel corners */
363 corner(030, 050, 060);
364 corner(051, 031, 061);
365 corner(032, 062, 052);
366 corner(064, 054, 034);
367 corner(036, 056, 066);
368 corner(065, 035, 055);
369 corner(053, 063, 033);
370 corner(037, 067, 057);
371 }
372 if (bevel > 0.0 && rounde) { /* round edges */
373 cylinder(070, 071);
374 cylinder(070, 074);
375 cylinder(070, 072);
376 cylinder(073, 071);
377 cylinder(073, 072);
378 cylinder(073, 077);
379 cylinder(075, 071);
380 cylinder(075, 074);
381 cylinder(075, 077);
382 cylinder(076, 072);
383 cylinder(076, 074);
384 cylinder(076, 077);
385 /* round corners */
386 sphere(070);
387 sphere(071);
388 sphere(072);
389 sphere(073);
390 sphere(074);
391 sphere(075);
392 sphere(076);
393 sphere(077);
394 }
395 if (bevel == 0.0) { /* only need major faces */
396 side(1, 5, 4, 0);
397 side(4, 6, 2, 0);
398 side(2, 3, 1, 0);
399 side(3, 2, 6, 7);
400 side(5, 1, 3, 7);
401 side(6, 4, 5, 7);
402 }
403 if (obj != NULL) { /* need to write output? */
404 if (!smooth)
405 removeNormals(obj, 0, 0);
406 if (objout) {
407 if (rounde) /* joins corners to edges */
408 coalesceVertices(obj, 2.*FTINY);
409 if (toOBJ(obj, stdout) <= 0)
410 return(1);
411 } else if (toRadiance(obj, stdout, 0, 0) <= 0)
412 return(1);
413 /* freeScene(obj); we're exiting, anyway... */
414 }
415 return(0);
416 userr:
417 fprintf(stderr, "Usage: %s ", argv[0]);
418 fprintf(stderr, "material name xsize ysize zsize ");
419 fprintf(stderr, "[-i] [-b bevel | -r round [-n nsegs][-s]] [-o]\n");
420 return(1);
421 }