ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/ot/cvmesh.c
Revision: 2.10
Committed: Thu Nov 25 14:45:38 2004 UTC (20 years ago) by greg
Content type: text/plain
Branch: MAIN
CVS Tags: rad3R7P2, rad3R7P1, rad4R0, rad3R8, rad3R9
Changes since 2.9: +2 -2 lines
Log Message:
Minor bug fix for .OBJ files with all identical texture coordinates

File Contents

# Content
1 #ifndef lint
2 static const char RCSid[] = "$Id: cvmesh.c,v 2.9 2004/03/27 12:41:45 schorsch Exp $";
3 #endif
4 /*
5 * Radiance triangle mesh conversion routines
6 */
7
8 #include "copyright.h"
9 #include "standard.h"
10 #include "cvmesh.h"
11 #include "otypes.h"
12 #include "face.h"
13 #include "tmesh.h"
14
15 /*
16 * We need to divide faces into triangles and record auxiliary information
17 * if given (surface normal and uv coordinates). We do this by extending
18 * the face structure linked to the OBJREC os member and putting our
19 * auxiliary after it -- a bit sly, but it works.
20 */
21
22 /* Auxiliary data for triangle */
23 typedef struct {
24 int fl; /* flags of what we're storing */
25 OBJECT obj; /* mesh triangle ID */
26 FVECT vn[3]; /* normals */
27 RREAL vc[3][2]; /* uv coords. */
28 } TRIDATA;
29
30 #define tdsize(fl) ((fl)&MT_UV ? sizeof(TRIDATA) : \
31 (fl)&MT_N ? sizeof(TRIDATA)-6*sizeof(RREAL) : \
32 sizeof(int)+sizeof(OBJECT))
33
34 #define OMARGIN (10*FTINY) /* margin around global cube */
35
36 MESH *ourmesh = NULL; /* our global mesh data structure */
37
38 FVECT meshbounds[2]; /* mesh bounding box */
39
40 static void add2bounds(FVECT vp, RREAL vc[2]);
41 static OBJECT cvmeshtri(OBJECT obj);
42 static OCTREE cvmeshoct(OCTREE ot);
43
44
45
46 MESH *
47 cvinit( /* initialize empty mesh */
48 char *nm
49 )
50 {
51 /* free old mesh, first */
52 if (ourmesh != NULL) {
53 freemesh(ourmesh);
54 ourmesh = NULL;
55 freeobjects(0, nobjects);
56 donesets();
57 }
58 if (nm == NULL)
59 return(NULL);
60 ourmesh = (MESH *)calloc(1, sizeof(MESH));
61 if (ourmesh == NULL)
62 goto nomem;
63 ourmesh->name = savestr(nm);
64 ourmesh->nref = 1;
65 ourmesh->ldflags = 0;
66 ourmesh->mcube.cutree = EMPTY;
67 ourmesh->uvlim[0][0] = ourmesh->uvlim[0][1] = FHUGE;
68 ourmesh->uvlim[1][0] = ourmesh->uvlim[1][1] = -FHUGE;
69 meshbounds[0][0] = meshbounds[0][1] = meshbounds[0][2] = FHUGE;
70 meshbounds[1][0] = meshbounds[1][1] = meshbounds[1][2] = -FHUGE;
71 return(ourmesh);
72 nomem:
73 error(SYSTEM, "out of memory in cvinit");
74 return(NULL);
75 }
76
77
78 int
79 cvpoly( /* convert a polygon to extended triangles */
80 OBJECT mo,
81 int n,
82 FVECT *vp,
83 FVECT *vn,
84 RREAL (*vc)[2]
85 )
86 {
87 int tcnt = 0;
88 int flags;
89 RREAL *tn[3], *tc[3];
90 int *ord;
91 int i, j;
92
93 if (n < 3) /* degenerate face */
94 return(0);
95 flags = MT_V;
96 if (vn != NULL) {
97 tn[0] = vn[0]; tn[1] = vn[1]; tn[2] = vn[2];
98 flags |= MT_N;
99 } else {
100 tn[0] = tn[1] = tn[2] = NULL;
101 }
102 if (vc != NULL) {
103 tc[0] = vc[0]; tc[1] = vc[1]; tc[2] = vc[2];
104 flags |= MT_UV;
105 } else {
106 tc[0] = tc[1] = tc[2] = NULL;
107 }
108 if (n == 3) /* output single triangle */
109 return(cvtri(mo, vp[0], vp[1], vp[2],
110 tn[0], tn[1], tn[2],
111 tc[0], tc[1], tc[2]));
112
113 /* decimate polygon (assumes convex) */
114 ord = (int *)malloc(n*sizeof(int));
115 if (ord == NULL)
116 error(SYSTEM, "out of memory in cvpoly");
117 for (i = n; i--; )
118 ord[i] = i;
119 while (n >= 3) {
120 if (flags & MT_N)
121 for (i = 3; i--; )
122 tn[i] = vn[ord[i]];
123 if (flags & MT_UV)
124 for (i = 3; i--; )
125 tc[i] = vc[ord[i]];
126 tcnt += cvtri(mo, vp[ord[0]], vp[ord[1]], vp[ord[2]],
127 tn[0], tn[1], tn[2],
128 tc[0], tc[1], tc[2]);
129 /* remove vertex and rotate */
130 n--;
131 j = ord[0];
132 for (i = 0; i < n-1; i++)
133 ord[i] = ord[i+2];
134 ord[i] = j;
135 }
136 free((void *)ord);
137 return(tcnt);
138 }
139
140
141 static void
142 add2bounds( /* add point and uv coordinate to bounds */
143 FVECT vp,
144 RREAL vc[2]
145 )
146 {
147 register int j;
148
149 for (j = 3; j--; ) {
150 if (vp[j] < meshbounds[0][j])
151 meshbounds[0][j] = vp[j];
152 if (vp[j] > meshbounds[1][j])
153 meshbounds[1][j] = vp[j];
154 }
155 if (vc == NULL)
156 return;
157 for (j = 2; j--; ) {
158 if (vc[j] < ourmesh->uvlim[0][j])
159 ourmesh->uvlim[0][j] = vc[j];
160 if (vc[j] > ourmesh->uvlim[1][j])
161 ourmesh->uvlim[1][j] = vc[j];
162 }
163 }
164
165
166 int /* create an extended triangle */
167 cvtri(
168 OBJECT mo,
169 FVECT vp1,
170 FVECT vp2,
171 FVECT vp3,
172 FVECT vn1,
173 FVECT vn2,
174 FVECT vn3,
175 RREAL vc1[2],
176 RREAL vc2[2],
177 RREAL vc3[2]
178 )
179 {
180 static OBJECT fobj = OVOID;
181 char buf[32];
182 int flags;
183 TRIDATA *ts;
184 FACE *f;
185 OBJREC *fop;
186 int j;
187
188 flags = MT_V; /* check what we have */
189 if (vn1 != NULL && vn2 != NULL && vn3 != NULL) {
190 RREAL *rp;
191 switch (flat_tri(vp1, vp2, vp3, vn1, vn2, vn3)) {
192 case ISBENT:
193 flags |= MT_N;
194 /* fall through */
195 case ISFLAT:
196 break;
197 case RVBENT:
198 flags |= MT_N;
199 rp = vn1; vn1 = vn3; vn3 = rp;
200 /* fall through */
201 case RVFLAT:
202 rp = vp1; vp1 = vp3; vp3 = rp;
203 rp = vc1; vc1 = vc3; vc3 = rp;
204 break;
205 case DEGEN:
206 error(WARNING, "degenerate triangle");
207 return(0);
208 default:
209 error(INTERNAL, "bad return from flat_tri()");
210 }
211 }
212 if (vc1 != NULL && vc2 != NULL && vc3 != NULL)
213 flags |= MT_UV;
214 if (fobj == OVOID) { /* create new triangle object */
215 fobj = newobject();
216 if (fobj == OVOID)
217 goto nomem;
218 fop = objptr(fobj);
219 fop->omod = mo;
220 fop->otype = OBJ_FACE;
221 sprintf(buf, "t%ld", fobj);
222 fop->oname = savqstr(buf);
223 fop->oargs.nfargs = 9;
224 fop->oargs.farg = (RREAL *)malloc(9*sizeof(RREAL));
225 if (fop->oargs.farg == NULL)
226 goto nomem;
227 } else { /* else reuse failed one */
228 fop = objptr(fobj);
229 if (fop->otype != OBJ_FACE || fop->oargs.nfargs != 9)
230 error(CONSISTENCY, "code error 1 in cvtri");
231 }
232 for (j = 3; j--; ) {
233 fop->oargs.farg[j] = vp1[j];
234 fop->oargs.farg[3+j] = vp2[j];
235 fop->oargs.farg[6+j] = vp3[j];
236 }
237 /* create face record */
238 f = getface(fop);
239 if (f->area == 0.) {
240 free_os(fop);
241 return(0);
242 }
243 if (fop->os != (char *)f)
244 error(CONSISTENCY, "code error 2 in cvtri");
245 /* follow with auxliary data */
246 f = (FACE *)realloc((void *)f, sizeof(FACE)+tdsize(flags));
247 if (f == NULL)
248 goto nomem;
249 fop->os = (char *)f;
250 ts = (TRIDATA *)(f+1);
251 ts->fl = flags;
252 ts->obj = OVOID;
253 if (flags & MT_N)
254 for (j = 3; j--; ) {
255 ts->vn[0][j] = vn1[j];
256 ts->vn[1][j] = vn2[j];
257 ts->vn[2][j] = vn3[j];
258 }
259 if (flags & MT_UV)
260 for (j = 2; j--; ) {
261 ts->vc[0][j] = vc1[j];
262 ts->vc[1][j] = vc2[j];
263 ts->vc[2][j] = vc3[j];
264 }
265 else
266 vc1 = vc2 = vc3 = NULL;
267 /* update bounds */
268 add2bounds(vp1, vc1);
269 add2bounds(vp2, vc2);
270 add2bounds(vp3, vc3);
271 fobj = OVOID; /* we used this one */
272 return(1);
273 nomem:
274 error(SYSTEM, "out of memory in cvtri");
275 return(0);
276 }
277
278
279 static OBJECT
280 cvmeshtri( /* add an extended triangle to our mesh */
281 OBJECT obj
282 )
283 {
284 OBJREC *o = objptr(obj);
285 TRIDATA *ts;
286 MESHVERT vert[3];
287 int i, j;
288
289 if (o->otype != OBJ_FACE)
290 error(CONSISTENCY, "non-face in mesh");
291 if (o->oargs.nfargs != 9)
292 error(CONSISTENCY, "non-triangle in mesh");
293 if (o->os == NULL)
294 error(CONSISTENCY, "missing face record in cvmeshtri");
295 ts = (TRIDATA *)((FACE *)o->os + 1);
296 if (ts->obj != OVOID) /* already added? */
297 return(ts->obj);
298 vert[0].fl = vert[1].fl = vert[2].fl = ts->fl;
299 for (i = 3; i--; )
300 for (j = 3; j--; )
301 vert[i].v[j] = o->oargs.farg[3*i+j];
302 if (ts->fl & MT_N)
303 for (i = 3; i--; )
304 for (j = 3; j--; )
305 vert[i].n[j] = ts->vn[i][j];
306 if (ts->fl & MT_UV)
307 for (i = 3; i--; )
308 for (j = 2; j--; )
309 vert[i].uv[j] = ts->vc[i][j];
310 ts->obj = addmeshtri(ourmesh, vert, o->omod);
311 if (ts->obj == OVOID)
312 error(INTERNAL, "addmeshtri failed");
313 return(ts->obj);
314 }
315
316
317 void
318 cvmeshbounds(void) /* set mesh boundaries */
319 {
320 int i;
321
322 if (ourmesh == NULL)
323 return;
324 /* fix coordinate bounds */
325 for (i = 0; i < 3; i++) {
326 if (meshbounds[0][i] > meshbounds[1][i])
327 error(USER, "no polygons in mesh");
328 meshbounds[0][i] -= OMARGIN;
329 meshbounds[1][i] += OMARGIN;
330 if (meshbounds[1][i]-meshbounds[0][i] > ourmesh->mcube.cusize)
331 ourmesh->mcube.cusize = meshbounds[1][i] -
332 meshbounds[0][i];
333 }
334 for (i = 0; i < 3; i++)
335 ourmesh->mcube.cuorg[i] = (meshbounds[1][i]+meshbounds[0][i] -
336 ourmesh->mcube.cusize)*.5;
337 if (ourmesh->uvlim[0][0] > ourmesh->uvlim[1][0]) {
338 ourmesh->uvlim[0][0] = ourmesh->uvlim[0][1] = 0.;
339 ourmesh->uvlim[1][0] = ourmesh->uvlim[1][1] = 0.;
340 } else {
341 for (i = 0; i < 2; i++) {
342 double marg; /* expand past endpoints */
343 marg = (2./(1L<<(8*sizeof(uint16)))) *
344 (ourmesh->uvlim[1][i] -
345 ourmesh->uvlim[0][i]) + FTINY;
346 ourmesh->uvlim[0][i] -= marg;
347 ourmesh->uvlim[1][i] += marg;
348 }
349 }
350 ourmesh->ldflags |= IO_BOUNDS;
351 }
352
353
354 static OCTREE
355 cvmeshoct( /* convert triangles in subtree */
356 OCTREE ot
357 )
358 {
359 int i;
360
361 if (isempty(ot))
362 return(EMPTY);
363
364 if (isfull(ot)) {
365 OBJECT oset1[MAXSET+1];
366 OBJECT oset2[MAXSET+1];
367 objset(oset1, ot);
368 oset2[0] = 0;
369 for (i = oset1[0]; i > 0; i--)
370 insertelem(oset2, cvmeshtri(oset1[i]));
371 return(fullnode(oset2));
372 }
373
374 for (i = 8; i--; )
375 octkid(ot, i) = cvmeshoct(octkid(ot, i));
376 return(ot);
377 }
378
379
380 MESH *
381 cvmesh(void) /* convert mesh and octree leaf nodes */
382 {
383 if (ourmesh == NULL)
384 return(NULL);
385 /* convert triangles in octree nodes */
386 ourmesh->mcube.cutree = cvmeshoct(ourmesh->mcube.cutree);
387 ourmesh->ldflags |= IO_SCENE|IO_TREE;
388
389 return(ourmesh);
390 }