ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/gen/gensurf.c
Revision: 2.9
Committed: Wed Mar 12 04:59:04 2003 UTC (21 years, 7 months ago) by greg
Content type: text/plain
Branch: MAIN
CVS Tags: rad3R5
Changes since 2.8: +26 -20 lines
Log Message:
Numerous bug fixes in new mesh code

File Contents

# Content
1 #ifndef lint
2 static const char RCSid[] = "$Id$";
3 #endif
4 /*
5 * gensurf.c - program to generate functional surfaces
6 *
7 * Parametric functions x(s,t), y(s,t) and z(s,t)
8 * specify the surface, which is tesselated into an m by n
9 * array of paired triangles.
10 * The surface normal is defined by the right hand
11 * rule applied to (s,t).
12 *
13 * 4/3/87
14 *
15 * 4/16/02 Added conditional vertex output
16 */
17
18 #include "standard.h"
19
20 char XNAME[] = "X`SYS"; /* x function name */
21 char YNAME[] = "Y`SYS"; /* y function name */
22 char ZNAME[] = "Z`SYS"; /* z function name */
23
24 char VNAME[] = "valid"; /* valid vertex name */
25
26 #define ABS(x) ((x)>=0 ? (x) : -(x))
27
28 #define ZEROVECT(v) (DOT(v,v) <= FTINY*FTINY)
29
30 #define pvect(p) printf(vformat, (p)[0], (p)[1], (p)[2])
31
32 char vformat[] = "%15.9g %15.9g %15.9g\n";
33 char tsargs[] = "4 surf_dx surf_dy surf_dz surf.cal\n";
34 char texname[] = "Phong";
35
36 int smooth = 0; /* apply smoothing? */
37 int objout = 0; /* output .OBJ format? */
38
39 char *modname, *surfname;
40
41 /* recorded data flags */
42 #define HASBORDER 01
43 #define TRIPLETS 02
44 /* a data structure */
45 struct {
46 int flags; /* data type */
47 short m, n; /* number of s and t values */
48 FLOAT *data; /* the data itself, s major sort */
49 } datarec; /* our recorded data */
50
51 double l_hermite(), l_bezier(), l_bspline(), l_dataval();
52 extern double funvalue(), argument();
53
54 typedef struct {
55 int valid; /* point is valid (vertex number) */
56 FVECT p; /* vertex position */
57 FVECT n; /* average normal */
58 FLOAT uv[2]; /* (u,v) position */
59 } POINT;
60
61
62 main(argc, argv)
63 int argc;
64 char *argv[];
65 {
66 extern long eclock;
67 POINT *row0, *row1, *row2, *rp;
68 int i, j, m, n;
69 char stmp[256];
70
71 varset("PI", ':', PI);
72 funset("hermite", 5, ':', l_hermite);
73 funset("bezier", 5, ':', l_bezier);
74 funset("bspline", 5, ':', l_bspline);
75
76 if (argc < 8)
77 goto userror;
78
79 for (i = 8; i < argc; i++)
80 if (!strcmp(argv[i], "-e"))
81 scompile(argv[++i], NULL, 0);
82 else if (!strcmp(argv[i], "-f"))
83 fcompile(argv[++i]);
84 else if (!strcmp(argv[i], "-s"))
85 smooth++;
86 else if (!strcmp(argv[i], "-o"))
87 objout++;
88 else
89 goto userror;
90
91 modname = argv[1];
92 surfname = argv[2];
93 m = atoi(argv[6]);
94 n = atoi(argv[7]);
95 if (m <= 0 || n <= 0)
96 goto userror;
97 if (!strcmp(argv[5], "-") || access(argv[5], 4) == 0) { /* file? */
98 funset(ZNAME, 2, ':', l_dataval);
99 if (!strcmp(argv[5],argv[3]) && !strcmp(argv[5],argv[4])) {
100 loaddata(argv[5], m, n, 3);
101 funset(XNAME, 2, ':', l_dataval);
102 funset(YNAME, 2, ':', l_dataval);
103 } else {
104 loaddata(argv[5], m, n, 1);
105 sprintf(stmp, "%s(s,t)=%s;", XNAME, argv[3]);
106 scompile(stmp, NULL, 0);
107 sprintf(stmp, "%s(s,t)=%s;", YNAME, argv[4]);
108 scompile(stmp, NULL, 0);
109 }
110 } else {
111 sprintf(stmp, "%s(s,t)=%s;", XNAME, argv[3]);
112 scompile(stmp, NULL, 0);
113 sprintf(stmp, "%s(s,t)=%s;", YNAME, argv[4]);
114 scompile(stmp, NULL, 0);
115 sprintf(stmp, "%s(s,t)=%s;", ZNAME, argv[5]);
116 scompile(stmp, NULL, 0);
117 }
118 row0 = (POINT *)malloc((n+3)*sizeof(POINT));
119 row1 = (POINT *)malloc((n+3)*sizeof(POINT));
120 row2 = (POINT *)malloc((n+3)*sizeof(POINT));
121 if (row0 == NULL || row1 == NULL || row2 == NULL) {
122 fprintf(stderr, "%s: out of memory\n", argv[0]);
123 quit(1);
124 }
125 row0++; row1++; row2++;
126 /* print header */
127 printhead(argc, argv);
128 eclock = 0;
129 /* initialize */
130 comprow(-1.0/m, row0, n);
131 comprow(0.0, row1, n);
132 comprow(1.0/m, row2, n);
133 compnorms(row0, row1, row2, n);
134 if (objout) {
135 printf("\nusemtl %s\n\n", modname);
136 putobjrow(row1, n);
137 }
138 /* for each row */
139 for (i = 0; i < m; i++) {
140 /* compute next row */
141 rp = row0;
142 row0 = row1;
143 row1 = row2;
144 row2 = rp;
145 comprow((double)(i+2)/m, row2, n);
146 compnorms(row0, row1, row2, n);
147 if (objout)
148 putobjrow(row1, n);
149
150 for (j = 0; j < n; j++) {
151 int orient = (j & 1);
152 /* put polygons */
153 if (!(row0[j].valid && row1[j+1].valid))
154 orient = 1;
155 else if (!(row1[j].valid && row0[j+1].valid))
156 orient = 0;
157 if (orient)
158 putsquare(&row0[j], &row1[j],
159 &row0[j+1], &row1[j+1]);
160 else
161 putsquare(&row1[j], &row1[j+1],
162 &row0[j], &row0[j+1]);
163 }
164 }
165
166 quit(0);
167
168 userror:
169 fprintf(stderr, "Usage: %s material name ", argv[0]);
170 fprintf(stderr, "x(s,t) y(s,t) z(s,t) m n [-s][-e expr][-f file]\n");
171 quit(1);
172 }
173
174
175 loaddata(file, m, n, pointsize) /* load point data from file */
176 char *file;
177 int m, n;
178 int pointsize;
179 {
180 FILE *fp;
181 char word[64];
182 register int size;
183 register FLOAT *dp;
184
185 datarec.flags = HASBORDER; /* assume border values */
186 datarec.m = m+1;
187 datarec.n = n+1;
188 size = datarec.m*datarec.n*pointsize;
189 if (pointsize == 3)
190 datarec.flags |= TRIPLETS;
191 dp = (FLOAT *)malloc(size*sizeof(FLOAT));
192 if ((datarec.data = dp) == NULL) {
193 fputs("Out of memory\n", stderr);
194 exit(1);
195 }
196 if (!strcmp(file, "-")) {
197 file = "<stdin>";
198 fp = stdin;
199 } else if ((fp = fopen(file, "r")) == NULL) {
200 fputs(file, stderr);
201 fputs(": cannot open\n", stderr);
202 exit(1);
203 }
204 while (size > 0 && fgetword(word, sizeof(word), fp) != NULL) {
205 if (!isflt(word)) {
206 fprintf(stderr, "%s: garbled data value: %s\n",
207 file, word);
208 exit(1);
209 }
210 *dp++ = atof(word);
211 size--;
212 }
213 if (size == (m+n+1)*pointsize) { /* no border after all */
214 dp = (FLOAT *)realloc((char *)datarec.data,
215 m*n*pointsize*sizeof(FLOAT));
216 if (dp != NULL)
217 datarec.data = dp;
218 datarec.flags &= ~HASBORDER;
219 datarec.m = m;
220 datarec.n = n;
221 size = 0;
222 }
223 if (datarec.m < 2 || datarec.n < 2 || size != 0 ||
224 fgetword(word, sizeof(word), fp) != NULL) {
225 fputs(file, stderr);
226 fputs(": bad number of data points\n", stderr);
227 exit(1);
228 }
229 fclose(fp);
230 }
231
232
233 double
234 l_dataval(nam) /* return recorded data value */
235 char *nam;
236 {
237 double u, v;
238 register int i, j;
239 register FLOAT *dp;
240 double d00, d01, d10, d11;
241 /* compute coordinates */
242 u = argument(1); v = argument(2);
243 if (datarec.flags & HASBORDER) {
244 i = u *= datarec.m-1;
245 j = v *= datarec.n-1;
246 } else {
247 i = u = u*datarec.m - .5;
248 j = v = v*datarec.n - .5;
249 }
250 if (i < 0) i = 0;
251 else if (i > datarec.m-2) i = datarec.m-2;
252 if (j < 0) j = 0;
253 else if (j > datarec.n-2) j = datarec.n-2;
254 /* compute value */
255 if (datarec.flags & TRIPLETS) {
256 dp = datarec.data + 3*(j*datarec.m + i);
257 if (nam == ZNAME)
258 dp += 2;
259 else if (nam == YNAME)
260 dp++;
261 d00 = dp[0]; d01 = dp[3];
262 dp += 3*datarec.m;
263 d10 = dp[0]; d11 = dp[3];
264 } else {
265 dp = datarec.data + j*datarec.m + i;
266 d00 = dp[0]; d01 = dp[1];
267 dp += datarec.m;
268 d10 = dp[0]; d11 = dp[1];
269 }
270 /* bilinear interpolation */
271 return((j+1-v)*((i+1-u)*d00+(u-i)*d01)+(v-j)*((i+1-u)*d10+(u-i)*d11));
272 }
273
274
275 putobjrow(rp, n) /* output vertex row to .OBJ */
276 register POINT *rp;
277 int n;
278 {
279 static int nverts = 0;
280
281 for ( ; n-- >= 0; rp++) {
282 if (!rp->valid)
283 continue;
284 fputs("v ", stdout);
285 pvect(rp->p);
286 if (smooth && !ZEROVECT(rp->n))
287 printf("\tvn %.9g %.9g %.9g\n",
288 rp->n[0], rp->n[1], rp->n[2]);
289 printf("\tvt %.9g %.9g\n", rp->uv[0], rp->uv[1]);
290 rp->valid = ++nverts;
291 }
292 }
293
294
295 putsquare(p0, p1, p2, p3) /* put out a square */
296 POINT *p0, *p1, *p2, *p3;
297 {
298 static int nout = 0;
299 FVECT norm[4];
300 int axis;
301 FVECT v1, v2, vc1, vc2;
302 int ok1, ok2;
303 /* compute exact normals */
304 ok1 = (p0->valid && p1->valid && p2->valid);
305 if (ok1) {
306 VSUB(v1, p1->p, p0->p);
307 VSUB(v2, p2->p, p0->p);
308 fcross(vc1, v1, v2);
309 ok1 = (normalize(vc1) != 0.0);
310 }
311 ok2 = (p1->valid && p2->valid && p3->valid);
312 if (ok2) {
313 VSUB(v1, p2->p, p3->p);
314 VSUB(v2, p1->p, p3->p);
315 fcross(vc2, v1, v2);
316 ok2 = (normalize(vc2) != 0.0);
317 }
318 if (!(ok1 | ok2))
319 return;
320 if (objout) { /* output .OBJ faces */
321 int p0n=0, p1n=0, p2n=0, p3n=0;
322 if (smooth) {
323 if (!ZEROVECT(p0->n))
324 p0n = p0->valid;
325 if (!ZEROVECT(p1->n))
326 p1n = p1->valid;
327 if (!ZEROVECT(p2->n))
328 p2n = p2->valid;
329 if (!ZEROVECT(p3->n))
330 p3n = p3->valid;
331 }
332 if (ok1 & ok2 && fdot(vc1,vc2) >= 1.0-FTINY*FTINY) {
333 printf("f %d/%d/%d %d/%d/%d %d/%d/%d %d/%d/%d\n",
334 p0->valid, p0->valid, p0n,
335 p1->valid, p1->valid, p1n,
336 p3->valid, p3->valid, p3n,
337 p2->valid, p2->valid, p2n);
338 return;
339 }
340 if (ok1)
341 printf("f %d/%d/%d %d/%d/%d %d/%d/%d\n",
342 p0->valid, p0->valid, p0n,
343 p1->valid, p1->valid, p1n,
344 p2->valid, p2->valid, p2n);
345 if (ok2)
346 printf("f %d/%d/%d %d/%d/%d %d/%d/%d\n",
347 p2->valid, p2->valid, p2n,
348 p1->valid, p1->valid, p1n,
349 p3->valid, p3->valid, p3n);
350 return;
351 }
352 /* compute normal interpolation */
353 axis = norminterp(norm, p0, p1, p2, p3);
354
355 /* put out quadrilateral? */
356 if (ok1 & ok2 && fdot(vc1,vc2) >= 1.0-FTINY*FTINY) {
357 printf("\n%s ", modname);
358 if (axis != -1) {
359 printf("texfunc %s\n", texname);
360 printf(tsargs);
361 printf("0\n13\t%d\n", axis);
362 pvect(norm[0]);
363 pvect(norm[1]);
364 pvect(norm[2]);
365 fvsum(v1, norm[3], vc1, -0.5);
366 fvsum(v1, v1, vc2, -0.5);
367 pvect(v1);
368 printf("\n%s ", texname);
369 }
370 printf("polygon %s.%d\n", surfname, ++nout);
371 printf("0\n0\n12\n");
372 pvect(p0->p);
373 pvect(p1->p);
374 pvect(p3->p);
375 pvect(p2->p);
376 return;
377 }
378 /* put out triangles? */
379 if (ok1) {
380 printf("\n%s ", modname);
381 if (axis != -1) {
382 printf("texfunc %s\n", texname);
383 printf(tsargs);
384 printf("0\n13\t%d\n", axis);
385 pvect(norm[0]);
386 pvect(norm[1]);
387 pvect(norm[2]);
388 fvsum(v1, norm[3], vc1, -1.0);
389 pvect(v1);
390 printf("\n%s ", texname);
391 }
392 printf("polygon %s.%d\n", surfname, ++nout);
393 printf("0\n0\n9\n");
394 pvect(p0->p);
395 pvect(p1->p);
396 pvect(p2->p);
397 }
398 if (ok2) {
399 printf("\n%s ", modname);
400 if (axis != -1) {
401 printf("texfunc %s\n", texname);
402 printf(tsargs);
403 printf("0\n13\t%d\n", axis);
404 pvect(norm[0]);
405 pvect(norm[1]);
406 pvect(norm[2]);
407 fvsum(v2, norm[3], vc2, -1.0);
408 pvect(v2);
409 printf("\n%s ", texname);
410 }
411 printf("polygon %s.%d\n", surfname, ++nout);
412 printf("0\n0\n9\n");
413 pvect(p2->p);
414 pvect(p1->p);
415 pvect(p3->p);
416 }
417 }
418
419
420 comprow(s, row, siz) /* compute row of values */
421 double s;
422 register POINT *row;
423 int siz;
424 {
425 double st[2];
426 int end;
427 int checkvalid;
428 register int i;
429
430 if (smooth) {
431 i = -1; /* compute one past each end */
432 end = siz+1;
433 } else {
434 if (s < -FTINY || s > 1.0+FTINY)
435 return;
436 i = 0;
437 end = siz;
438 }
439 st[0] = s;
440 checkvalid = (fundefined(VNAME) == 2);
441 while (i <= end) {
442 st[1] = (double)i/siz;
443 if (checkvalid && funvalue(VNAME, 2, st) <= 0.0) {
444 row[i].valid = 0;
445 row[i].p[0] = row[i].p[1] = row[i].p[2] = 0.0;
446 row[i].uv[0] = row[i].uv[1] = 0.0;
447 } else {
448 row[i].valid = 1;
449 row[i].p[0] = funvalue(XNAME, 2, st);
450 row[i].p[1] = funvalue(YNAME, 2, st);
451 row[i].p[2] = funvalue(ZNAME, 2, st);
452 row[i].uv[0] = st[0];
453 row[i].uv[1] = st[1];
454 }
455 i++;
456 }
457 }
458
459
460 compnorms(r0, r1, r2, siz) /* compute row of averaged normals */
461 register POINT *r0, *r1, *r2;
462 int siz;
463 {
464 FVECT v1, v2;
465
466 if (!smooth) /* not needed if no smoothing */
467 return;
468 /* compute row 1 normals */
469 while (siz-- >= 0) {
470 if (!r1[0].valid)
471 continue;
472 if (!r0[0].valid) {
473 if (!r2[0].valid) {
474 r1[0].n[0] = r1[0].n[1] = r1[0].n[2] = 0.0;
475 continue;
476 }
477 fvsum(v1, r2[0].p, r1[0].p, -1.0);
478 } else if (!r2[0].valid)
479 fvsum(v1, r1[0].p, r0[0].p, -1.0);
480 else
481 fvsum(v1, r2[0].p, r0[0].p, -1.0);
482 if (!r1[-1].valid) {
483 if (!r1[1].valid) {
484 r1[0].n[0] = r1[0].n[1] = r1[0].n[2] = 0.0;
485 continue;
486 }
487 fvsum(v2, r1[1].p, r1[0].p, -1.0);
488 } else if (!r1[1].valid)
489 fvsum(v2, r1[0].p, r1[-1].p, -1.0);
490 else
491 fvsum(v2, r1[1].p, r1[-1].p, -1.0);
492 fcross(r1[0].n, v1, v2);
493 normalize(r1[0].n);
494 r0++; r1++; r2++;
495 }
496 }
497
498
499 int
500 norminterp(resmat, p0, p1, p2, p3) /* compute normal interpolation */
501 register FVECT resmat[4];
502 POINT *p0, *p1, *p2, *p3;
503 {
504 #define u ((ax+1)%3)
505 #define v ((ax+2)%3)
506
507 register int ax;
508 MAT4 eqnmat;
509 FVECT v1;
510 register int i, j;
511
512 if (!smooth) /* no interpolation if no smoothing */
513 return(-1);
514 /* find dominant axis */
515 VCOPY(v1, p0->n);
516 fvsum(v1, v1, p1->n, 1.0);
517 fvsum(v1, v1, p2->n, 1.0);
518 fvsum(v1, v1, p3->n, 1.0);
519 ax = ABS(v1[0]) > ABS(v1[1]) ? 0 : 1;
520 ax = ABS(v1[ax]) > ABS(v1[2]) ? ax : 2;
521 /* assign equation matrix */
522 eqnmat[0][0] = p0->p[u]*p0->p[v];
523 eqnmat[0][1] = p0->p[u];
524 eqnmat[0][2] = p0->p[v];
525 eqnmat[0][3] = 1.0;
526 eqnmat[1][0] = p1->p[u]*p1->p[v];
527 eqnmat[1][1] = p1->p[u];
528 eqnmat[1][2] = p1->p[v];
529 eqnmat[1][3] = 1.0;
530 eqnmat[2][0] = p2->p[u]*p2->p[v];
531 eqnmat[2][1] = p2->p[u];
532 eqnmat[2][2] = p2->p[v];
533 eqnmat[2][3] = 1.0;
534 eqnmat[3][0] = p3->p[u]*p3->p[v];
535 eqnmat[3][1] = p3->p[u];
536 eqnmat[3][2] = p3->p[v];
537 eqnmat[3][3] = 1.0;
538 /* invert matrix (solve system) */
539 if (!invmat4(eqnmat, eqnmat))
540 return(-1); /* no solution */
541 /* compute result matrix */
542 for (j = 0; j < 4; j++)
543 for (i = 0; i < 3; i++)
544 resmat[j][i] = eqnmat[j][0]*p0->n[i] +
545 eqnmat[j][1]*p1->n[i] +
546 eqnmat[j][2]*p2->n[i] +
547 eqnmat[j][3]*p3->n[i];
548 return(ax);
549
550 #undef u
551 #undef v
552 }
553
554
555 void
556 eputs(msg)
557 char *msg;
558 {
559 fputs(msg, stderr);
560 }
561
562
563 void
564 wputs(msg)
565 char *msg;
566 {
567 eputs(msg);
568 }
569
570
571 void
572 quit(code)
573 int code;
574 {
575 exit(code);
576 }
577
578
579 printhead(ac, av) /* print command header */
580 register int ac;
581 register char **av;
582 {
583 putchar('#');
584 while (ac--) {
585 putchar(' ');
586 fputs(*av++, stdout);
587 }
588 putchar('\n');
589 }
590
591
592 double
593 l_hermite()
594 {
595 double t;
596
597 t = argument(5);
598 return( argument(1)*((2.0*t-3.0)*t*t+1.0) +
599 argument(2)*(-2.0*t+3.0)*t*t +
600 argument(3)*((t-2.0)*t+1.0)*t +
601 argument(4)*(t-1.0)*t*t );
602 }
603
604
605 double
606 l_bezier()
607 {
608 double t;
609
610 t = argument(5);
611 return( argument(1) * (1.+t*(-3.+t*(3.-t))) +
612 argument(2) * 3.*t*(1.+t*(-2.+t)) +
613 argument(3) * 3.*t*t*(1.-t) +
614 argument(4) * t*t*t );
615 }
616
617
618 double
619 l_bspline()
620 {
621 double t;
622
623 t = argument(5);
624 return( argument(1) * (1./6.+t*(-1./2.+t*(1./2.-1./6.*t))) +
625 argument(2) * (2./3.+t*t*(-1.+1./2.*t)) +
626 argument(3) * (1./6.+t*(1./2.+t*(1./2.-1./2.*t))) +
627 argument(4) * (1./6.*t*t*t) );
628 }