ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/gen/replmarks.c
Revision: 2.23
Committed: Sat Jun 7 05:09:45 2025 UTC (12 days, 21 hours ago) by greg
Content type: text/plain
Branch: MAIN
CVS Tags: HEAD
Changes since 2.22: +1 -2 lines
Log Message:
refactor: Put some declarations into "paths.h" and included in "platform.h"

File Contents

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