ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/ot/obj2mesh.c
Revision: 2.18
Committed: Tue Jun 3 21:31:51 2025 UTC (42 hours, 21 minutes ago) by greg
Content type: text/plain
Branch: MAIN
CVS Tags: HEAD
Changes since 2.17: +3 -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: obj2mesh.c,v 2.17 2023/02/06 22:40:21 greg Exp $";
3 #endif
4 /*
5 * Main program to compile a Wavefront .OBJ file into a Radiance mesh
6 */
7
8 #include "copyright.h"
9 #include "paths.h"
10 #include "platform.h"
11 #include "standard.h"
12 #include "resolu.h"
13 #include "cvmesh.h"
14 #include "otypes.h"
15
16 extern int o_face(); /* XXX should go to a header file */
17
18 int o_default() { return(O_MISS); }
19
20 FUN ofun[NUMOTYPE] = INIT_OTYPE; /* needed for link resolution */
21
22 int nowarn = 0; /* supress warnings? */
23
24 int objlim = 9; /* # of objects before split */
25
26 int resolu = 16384; /* octree resolution limit */
27
28 double mincusize; /* minimum cube size from resolu */
29
30 static void addface(CUBE *cu, OBJECT obj);
31 static void add2full(CUBE *cu, OBJECT obj);
32
33
34 int
35 main( /* compile a .OBJ file into a mesh */
36 int argc,
37 char *argv[]
38 )
39 {
40 int verbose = 0;
41 char *cp;
42 int i, j;
43
44 fixargv0(argv[0]); /* sets global progname */
45
46 ofun[OBJ_FACE].funp = o_face;
47
48 for (i = 1; i < argc && argv[i][0] == '-'; i++)
49 switch (argv[i][1]) {
50 case 'n': /* set limit */
51 objlim = atoi(argv[++i]);
52 break;
53 case 'r': /* resolution limit */
54 resolu = atoi(argv[++i]);
55 break;
56 case 'a': /* material file */
57 readobj(argv[++i]);
58 break;
59 case 'l': /* library material */
60 cp = getpath(argv[++i], getrlibpath(), R_OK);
61 if (cp == NULL) {
62 sprintf(errmsg,
63 "cannot find library material: '%s'",
64 argv[i]);
65 error(SYSTEM, errmsg);
66 }
67 readobj(cp);
68 break;
69 case 'w': /* supress warnings */
70 nowarn = 1;
71 break;
72 case 'v': /* print mesh stats */
73 verbose = 1;
74 break;
75 default:
76 sprintf(errmsg, "unknown option: '%s'", argv[i]);
77 error(USER, errmsg);
78 break;
79 }
80
81 if (i < argc-2)
82 error(USER, "too many file arguments");
83 /* initialize mesh */
84 cvinit(i==argc-2 ? argv[i+1] : "<stdout>");
85 /* read .OBJ file into triangles */
86 if (i == argc)
87 wfreadobj(NULL);
88 else
89 wfreadobj(argv[i]);
90
91 cvmeshbounds(); /* set octree boundaries */
92
93 if (i == argc-2) /* open output file */
94 if (freopen(argv[i+1], "w", stdout) == NULL)
95 error(SYSTEM, "cannot open output file");
96 SET_FILE_BINARY(stdout);
97 newheader("RADIANCE", stdout); /* new binary file header */
98 printargs(i<argc ? i+1 : argc, argv, stdout);
99 fputformat(MESHFMT, stdout);
100 fputc('\n', stdout);
101
102 mincusize = ourmesh->mcube.cusize / resolu - FTINY;
103
104 for (i = 0; i < nobjects; i++) /* add triangles to octree */
105 if (objptr(i)->otype == OBJ_FACE)
106 addface(&ourmesh->mcube, i);
107
108 /* optimize octree */
109 ourmesh->mcube.cutree = combine(ourmesh->mcube.cutree);
110
111 if (ourmesh->mcube.cutree == EMPTY)
112 error(WARNING, "mesh is empty");
113
114 cvmesh(); /* convert mesh and leaf nodes */
115
116 writemesh(ourmesh, stdout); /* write mesh to output */
117
118 if (verbose)
119 printmeshstats(ourmesh, stderr);
120
121 quit(0);
122 return 0; /* pro forma return */
123 }
124
125
126 void
127 quit( /* exit program */
128 int code
129 )
130 {
131 exit(code);
132 }
133
134
135 void
136 cputs(void) /* interactive error */
137 {
138 /* referenced, but not used */
139 }
140
141
142 void
143 wputs( /* warning message */
144 const char *s
145 )
146 {
147 if (!nowarn)
148 eputs(s);
149 }
150
151
152 void
153 eputs( /* put string to stderr */
154 const char *s
155 )
156 {
157 static int inln = 0;
158
159 if (!inln++) {
160 fputs(progname, stderr);
161 fputs(": ", stderr);
162 }
163 fputs(s, stderr);
164 if (*s && s[strlen(s)-1] == '\n')
165 inln = 0;
166 }
167
168
169 static void
170 addface( /* add a face to a cube */
171 CUBE *cu,
172 OBJECT obj
173 )
174 {
175
176 if (o_face(objptr(obj), cu) == O_MISS)
177 return;
178
179 if (istree(cu->cutree)) {
180 CUBE cukid; /* do children */
181 int i, j;
182 cukid.cusize = cu->cusize * 0.5;
183 for (i = 0; i < 8; i++) {
184 cukid.cutree = octkid(cu->cutree, i);
185 for (j = 0; j < 3; j++) {
186 cukid.cuorg[j] = cu->cuorg[j];
187 if ((1<<j) & i)
188 cukid.cuorg[j] += cukid.cusize;
189 }
190 addface(&cukid, obj);
191 octkid(cu->cutree, i) = cukid.cutree;
192 }
193 return;
194 }
195 if (isempty(cu->cutree)) {
196 OBJECT oset[2]; /* singular set */
197 oset[0] = 1; oset[1] = obj;
198 cu->cutree = fullnode(oset);
199 return;
200 }
201 /* add to full node */
202 add2full(cu, obj);
203 }
204
205
206 static void
207 add2full( /* add object to full node */
208 CUBE *cu,
209 OBJECT obj
210 )
211 {
212 OCTREE ot;
213 OBJECT oset[MAXSET+1];
214 CUBE cukid;
215 int i, j;
216
217 objset(oset, cu->cutree);
218 cukid.cusize = cu->cusize * 0.5;
219
220 if (oset[0] < objlim || cukid.cusize <
221 (oset[0] < MAXSET ? mincusize : mincusize/256.0)) {
222 /* add to set */
223 if (oset[0] >= MAXSET) {
224 sprintf(errmsg, "set overflow in addobject (%s)",
225 objptr(obj)->oname);
226 error(INTERNAL, errmsg);
227 }
228 insertelem(oset, obj);
229 cu->cutree = fullnode(oset);
230 return;
231 }
232 /* subdivide cube */
233 if ((ot = octalloc()) == EMPTY)
234 error(SYSTEM, "out of octree space");
235 /* assign subcubes */
236 for (i = 0; i < 8; i++) {
237 cukid.cutree = EMPTY;
238 for (j = 0; j < 3; j++) {
239 cukid.cuorg[j] = cu->cuorg[j];
240 if ((1<<j) & i)
241 cukid.cuorg[j] += cukid.cusize;
242 }
243 for (j = 1; j <= oset[0]; j++)
244 addface(&cukid, oset[j]);
245 addface(&cukid, obj);
246 /* returned node */
247 octkid(ot, i) = cukid.cutree;
248 }
249 cu->cutree = ot;
250 }