ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/gen/replmarks.c
Revision: 2.22
Committed: Tue Jun 3 21:31:51 2025 UTC (3 days, 3 hours ago) by greg
Content type: text/plain
Branch: MAIN
CVS Tags: HEAD
Changes since 2.21: +2 -4 lines
Log Message:
refactor: More consistent use of global char * progname and fixargv0()

File Contents

# Content
1 #ifndef lint
2 static const char RCSid[] = "$Id: replmarks.c,v 2.21 2025/04/23 01:57:04 greg Exp $";
3 #endif
4 /*
5 * Replace markers in Radiance scene description with objects or instances.
6 *
7 * Created: 17 Feb 1991 Greg Ward
8 */
9
10 #include <stdlib.h>
11 #include <ctype.h>
12 #include <math.h>
13 #include <stdio.h>
14
15 #include "platform.h"
16 #include "rtio.h"
17 #include "paths.h"
18 #include "fvect.h"
19
20 #ifdef M_PI
21 #define PI ((double)M_PI)
22 #else
23 #define PI 3.14159265358979323846
24 #endif
25
26 #define MAXVERT 6 /* maximum number of vertices for markers */
27 #define MAXMARK 128 /* maximum number of markers */
28
29 #define USE_XFORM 1 /* use !xform inline command */
30 #define USE_INSTANCE 2 /* use instance primitive */
31 #define USE_MESH 3 /* use mesh primitive */
32
33 typedef struct {
34 short beg, end; /* beginning and ending vertex */
35 float len2; /* length squared */
36 } EDGE; /* a marker edge */
37
38 struct mrkr {
39 char *modout; /* output modifier */
40 double mscale; /* scale by this to get unit */
41 char *modin; /* input modifier indicating marker */
42 char *objname; /* output object file or octree */
43 int usetype; /* one of USE_* above */
44 } marker[MAXMARK+1]; /* array of markers */
45 int nmarkers = 0; /* number of markers */
46
47 int expand; /* expand commands? */
48
49 static void convert(char *name, FILE *fin);
50 static void cvcomm(char *fname, FILE *fin);
51 static void cvobject(char *fname, FILE *fin);
52 static void replace(char *fname, struct mrkr *m, char *mark, FILE *fin);
53 static int edgecmp(const void *e1, const void *e2);
54 static int buildxf(char *xf, double markscale, FILE *fin);
55 static int addrot(char *xf, FVECT xp, FVECT yp, FVECT zp);
56
57
58 int
59 main(
60 int argc,
61 char *argv[]
62 )
63 {
64 FILE *fp;
65 int i, j;
66
67 fixargv0(argv[0]); /* sets global progname */
68 i = 1;
69 while (i < argc && argv[i][0] == '-') {
70 do {
71 switch (argv[i][1]) {
72 case 'i':
73 marker[nmarkers].usetype = USE_INSTANCE;
74 marker[nmarkers].objname = argv[++i];
75 break;
76 case 'I':
77 marker[nmarkers].usetype = USE_MESH;
78 marker[nmarkers].objname = argv[++i];
79 break;
80 case 'x':
81 marker[nmarkers].usetype = USE_XFORM;
82 marker[nmarkers].objname = argv[++i];
83 break;
84 case 'e':
85 expand = 1;
86 break;
87 case 'm':
88 marker[nmarkers].modout = argv[++i];
89 break;
90 case 's':
91 marker[nmarkers].mscale = atof(argv[++i]);
92 break;
93 default:
94 goto userr;
95 }
96 if (++i >= argc)
97 goto userr;
98 } while (argv[i][0] == '-');
99 if (marker[nmarkers].objname == NULL)
100 goto userr;
101 if (nmarkers >= MAXMARK) {
102 fprintf(stderr, "%s: too many markers\n", progname);
103 return 1;
104 }
105 marker[nmarkers++].modin = argv[i++];
106 marker[nmarkers].mscale = marker[nmarkers-1].mscale;
107 }
108 if (nmarkers == 0)
109 goto userr;
110 /* simple header */
111 putchar('#');
112 for (j = 0; j < i; j++) {
113 putchar(' ');
114 fputs(argv[j], stdout);
115 }
116 putchar('\n');
117 if (i == argc)
118 convert("<stdin>", stdin);
119 else
120 for ( ; i < argc; i++) {
121 if ((fp = fopen(argv[i], "r")) == NULL) {
122 perror(argv[i]);
123 exit(1);
124 }
125 convert(argv[i], fp);
126 fclose(fp);
127 }
128 return 0;
129 userr:
130 fprintf(stderr,
131 "Usage: %s [-e][-s size][-m modout] {-x objfile|-i octree|-I mesh} modname .. [file ..]\n",
132 progname);
133 return 1;
134 }
135
136
137 void
138 convert( /* replace marks in a stream */
139 char *name,
140 FILE *fin
141 )
142 {
143 int c;
144
145 while ((c = getc(fin)) != EOF) {
146 if (isspace(c)) /* blank */
147 continue;
148 if (c == '#') { /* comment */
149 putchar(c);
150 do {
151 if ((c = getc(fin)) == EOF)
152 return;
153 putchar(c);
154 } while (c != '\n');
155 } else if (c == '!') { /* command */
156 ungetc(c, fin);
157 cvcomm(name, fin);
158 } else { /* object */
159 ungetc(c, fin);
160 cvobject(name, fin);
161 }
162 }
163 }
164
165
166 void
167 cvcomm( /* convert a command */
168 char *fname,
169 FILE *fin
170 )
171 {
172 FILE *pin;
173 char buf[512];
174
175 fgetline(buf, sizeof(buf), fin);
176 if (expand) {
177 if ((pin = popen(buf+1, "r")) == NULL) {
178 fprintf(stderr,
179 "%s: (%s): cannot execute \"%s\"\n",
180 progname, fname, buf);
181 exit(1);
182 }
183 convert(buf, pin);
184 if (pclose(pin) != 0)
185 fprintf(stderr,
186 "%s: (%s): warning - bad status from \"%s\"\n",
187 progname, fname, buf);
188 } else
189 printf("\n%s\n", buf);
190 }
191
192
193 void
194 cvobject( /* convert an object */
195 char *fname,
196 FILE *fin
197 )
198 {
199 char buf[128], typ[16], nam[128];
200 int i, n;
201 int j;
202
203 if (fgetword(buf, sizeof(buf), fin) == NULL ||
204 fgetword(typ, sizeof(typ), fin) == NULL ||
205 fgetword(nam, sizeof(nam), fin) == NULL)
206 goto readerr;
207 if (!strcmp(typ, "polygon"))
208 for (j = 0; j < nmarkers; j++)
209 if (!strcmp(buf, marker[j].modin)) {
210 replace(fname, &marker[j], nam, fin);
211 return;
212 }
213 putchar('\n'); fputword(buf, stdout);
214 printf(" %s ", typ);
215 fputword(nam, stdout); putchar('\n');
216 if (!strcmp(typ, "alias")) { /* alias special case */
217 if (fgetword(buf, sizeof(buf), fin) == NULL)
218 goto readerr;
219 putchar('\t'); fputword(buf, stdout); putchar('\n');
220 return;
221 }
222 for (i = 0; i < 3; i++) { /* pass along arguments */
223 if (fscanf(fin, "%d", &n) != 1)
224 goto readerr;
225 printf("%d", n);
226 for (j = 0; j < n; j++) {
227 if (fgetword(buf, sizeof(buf), fin) == NULL)
228 goto readerr;
229 if (j%3 == 0)
230 putchar('\n');
231 putchar('\t');
232 fputword(buf, stdout);
233 }
234 putchar('\n');
235 }
236 return;
237 readerr:
238 fprintf(stderr, "%s: (%s): read error for %s \"%s\"\n",
239 progname, fname, typ, nam);
240 }
241
242
243 void
244 replace( /* replace marker */
245 char *fname,
246 struct mrkr *m,
247 char *mark,
248 FILE *fin
249 )
250 {
251 int n;
252 char buf[256];
253
254 buf[0] = '\0'; /* bug fix thanks to schorsch */
255 if (m->usetype == USE_XFORM) {
256 sprintf(buf, "xform -n %s", mark);
257 if (m->modout != NULL)
258 sprintf(buf+strlen(buf), " -m %s", m->modout);
259 if (buildxf(buf+strlen(buf), m->mscale, fin) < 0)
260 goto badxf;
261 sprintf(buf+strlen(buf), " %s", m->objname);
262 if (expand) {
263 fflush(stdout);
264 system(buf);
265 } else
266 printf("\n!%s\n", buf);
267 } else {
268 if ((n = buildxf(buf, m->mscale, fin)) < 0)
269 goto badxf;
270 printf("\n%s %s %s\n",
271 m->modout==NULL?"void":m->modout,
272 m->usetype==USE_INSTANCE?"instance":"mesh",
273 mark);
274 printf("%d %s%s\n0\n0\n", n+1, m->objname, buf);
275 }
276 return;
277 badxf:
278 fprintf(stderr, "%s: (%s): bad arguments for marker \"%s\"\n",
279 progname, fname, mark);
280 exit(1);
281 }
282
283
284 int
285 edgecmp( /* compare two edges, descending order */
286 const void *e1,
287 const void *e2
288 )
289 {
290 if (((EDGE*)e1)->len2 > ((EDGE*)e2)->len2)
291 return(-1);
292 if (((EDGE*)e1)->len2 < ((EDGE*)e2)->len2)
293 return(1);
294 return(0);
295 }
296
297
298 int
299 buildxf( /* build transform for marker */
300 char *xf,
301 double markscale,
302 FILE *fin
303 )
304 {
305 static FVECT vlist[MAXVERT];
306 static EDGE elist[MAXVERT];
307 FVECT xvec, yvec, zvec;
308 double xlen;
309 int n;
310 int i;
311 /*
312 * Read and sort vectors: longest is hypotenuse,
313 * second longest is x' axis,
314 * third longest is y' axis (approximate),
315 * other vectors are ignored.
316 * It is an error if the x' and y' axes do
317 * not share a common vertex (their origin).
318 */
319 if (fscanf(fin, "%*d %*d %d", &n) != 1)
320 return(-1);
321 if (n%3 != 0)
322 return(-1);
323 n /= 3;
324 if (n < 3 || n > MAXVERT)
325 return(-1);
326 /* sort edges in descending order */
327 for (i = 0; i < n; i++) {
328 if (fscanf(fin, "%lf %lf %lf", &vlist[i][0],
329 &vlist[i][1], &vlist[i][2]) != 3)
330 return(-1);
331 if (i) {
332 elist[i].beg = i-1;
333 elist[i].end = i;
334 elist[i].len2 = dist2(vlist[i-1],vlist[i]);
335 }
336 }
337 elist[0].beg = n-1;
338 elist[0].end = 0;
339 elist[0].len2 = dist2(vlist[n-1],vlist[0]);
340 qsort(elist, n, sizeof(EDGE), edgecmp);
341 /* find x' and y' */
342 if (elist[1].end == elist[2].beg || elist[1].end == elist[2].end) {
343 i = elist[1].beg;
344 elist[1].beg = elist[1].end;
345 elist[1].end = i;
346 }
347 if (elist[2].end == elist[1].beg) {
348 i = elist[2].beg;
349 elist[2].beg = elist[2].end;
350 elist[2].end = i;
351 }
352 if (elist[1].beg != elist[2].beg)
353 return(-1); /* x' and y' not connected! */
354 for (i = 0; i < 3; i++) {
355 xvec[i] = vlist[elist[1].end][i] - vlist[elist[1].beg][i];
356 yvec[i] = vlist[elist[2].end][i] - vlist[elist[2].beg][i];
357 }
358 if ((xlen = normalize(xvec)) == 0.0)
359 return(-1);
360 fcross(zvec, xvec, yvec);
361 if (normalize(zvec) == 0.0)
362 return(-1);
363 fcross(yvec, zvec, xvec);
364 n = 0; /* start transformation... */
365 if (markscale > 0.0) { /* add scale factor */
366 sprintf(xf, " -s %f", xlen*markscale);
367 n += 2;
368 while (*xf) ++xf;
369 }
370 /* add rotation */
371 n += addrot(xf, xvec, yvec, zvec);
372 while (*xf) ++xf;
373 /* add translation */
374 n += 4;
375 sprintf(xf, " -t %f %f %f", vlist[elist[1].beg][0],
376 vlist[elist[1].beg][1], vlist[elist[1].beg][2]);
377 return(n); /* all done */
378 }
379
380
381 int
382 addrot( /* compute rotation (x,y,z) => (xp,yp,zp) */
383 char *xf,
384 FVECT xp,
385 FVECT yp,
386 FVECT zp
387 )
388 {
389 int n;
390 double theta;
391
392 if (yp[2]*yp[2] + zp[2]*zp[2] < 2.*FTINY*FTINY) {
393 /* Special case for X' along Z-axis */
394 theta = -atan2(yp[0], yp[1]);
395 sprintf(xf, " -ry %f -rz %f",
396 xp[2] < 0.0 ? 90.0 : -90.0,
397 theta*(180./PI));
398 return(4);
399 }
400 n = 0;
401 theta = atan2(yp[2], zp[2]);
402 if (!FABSEQ(theta,0.0)) {
403 sprintf(xf, " -rx %f", theta*(180./PI));
404 while (*xf) ++xf;
405 n += 2;
406 }
407 theta = Asin(-xp[2]);
408 if (!FABSEQ(theta,0.0)) {
409 sprintf(xf, " -ry %f", theta*(180./PI));
410 while (*xf) ++xf;
411 n += 2;
412 }
413 theta = atan2(xp[1], xp[0]);
414 if (!FABSEQ(theta,0.0)) {
415 sprintf(xf, " -rz %f", theta*(180./PI));
416 /* while (*xf) ++xf; */
417 n += 2;
418 }
419 return(n);
420 }