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

# User Rev Content
1 greg 2.1 #ifndef lint
2 greg 2.10 static const char RCSid[] = "$Id: cvmesh.c,v 2.9 2004/03/27 12:41:45 schorsch Exp $";
3 greg 2.1 #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 greg 2.8 #include "tmesh.h"
14 greg 2.1
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 schorsch 2.6 RREAL vc[3][2]; /* uv coords. */
28 greg 2.1 } TRIDATA;
29    
30     #define tdsize(fl) ((fl)&MT_UV ? sizeof(TRIDATA) : \
31 schorsch 2.6 (fl)&MT_N ? sizeof(TRIDATA)-6*sizeof(RREAL) : \
32 greg 2.1 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 schorsch 2.9 static void add2bounds(FVECT vp, RREAL vc[2]);
41     static OBJECT cvmeshtri(OBJECT obj);
42     static OCTREE cvmeshoct(OCTREE ot);
43    
44    
45 greg 2.1
46     MESH *
47 schorsch 2.9 cvinit( /* initialize empty mesh */
48     char *nm
49     )
50 greg 2.1 {
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 greg 2.2 ourmesh->uvlim[0][0] = ourmesh->uvlim[0][1] = FHUGE;
68     ourmesh->uvlim[1][0] = ourmesh->uvlim[1][1] = -FHUGE;
69 greg 2.1 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 schorsch 2.9 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 greg 2.1 {
87     int tcnt = 0;
88     int flags;
89 schorsch 2.6 RREAL *tn[3], *tc[3];
90 greg 2.1 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 greg 2.3 return(cvtri(mo, vp[0], vp[1], vp[2],
110 greg 2.1 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 greg 2.3 tcnt += cvtri(mo, vp[ord[0]], vp[ord[1]], vp[ord[2]],
127 greg 2.1 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 schorsch 2.9 add2bounds( /* add point and uv coordinate to bounds */
143     FVECT vp,
144     RREAL vc[2]
145     )
146 greg 2.1 {
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 schorsch 2.9 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 greg 2.1 {
180 greg 2.3 static OBJECT fobj = OVOID;
181     char buf[32];
182     int flags;
183     TRIDATA *ts;
184     FACE *f;
185     OBJREC *fop;
186     int j;
187 greg 2.1
188 greg 2.8 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 greg 2.1 if (vc1 != NULL && vc2 != NULL && vc3 != NULL)
213     flags |= MT_UV;
214 greg 2.3 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 schorsch 2.9 sprintf(buf, "t%ld", fobj);
222 greg 2.3 fop->oname = savqstr(buf);
223     fop->oargs.nfargs = 9;
224 schorsch 2.6 fop->oargs.farg = (RREAL *)malloc(9*sizeof(RREAL));
225 greg 2.3 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 greg 2.1 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 greg 2.3 f = getface(fop);
239     if (f->area == 0.) {
240     free_os(fop);
241 greg 2.1 return(0);
242     }
243     if (fop->os != (char *)f)
244 greg 2.3 error(CONSISTENCY, "code error 2 in cvtri");
245 greg 2.1 /* 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 greg 2.3 fobj = OVOID; /* we used this one */
272 greg 2.1 return(1);
273     nomem:
274     error(SYSTEM, "out of memory in cvtri");
275     return(0);
276     }
277    
278    
279     static OBJECT
280 schorsch 2.9 cvmeshtri( /* add an extended triangle to our mesh */
281     OBJECT obj
282     )
283 greg 2.1 {
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 greg 2.3 ts->obj = addmeshtri(ourmesh, vert, o->omod);
311 greg 2.1 if (ts->obj == OVOID)
312     error(INTERNAL, "addmeshtri failed");
313     return(ts->obj);
314     }
315    
316    
317     void
318 schorsch 2.9 cvmeshbounds(void) /* set mesh boundaries */
319 greg 2.1 {
320     int i;
321    
322     if (ourmesh == NULL)
323     return;
324     /* fix coordinate bounds */
325     for (i = 0; i < 3; i++) {
326 greg 2.5 if (meshbounds[0][i] > meshbounds[1][i])
327 greg 2.1 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 greg 2.2 if (ourmesh->uvlim[0][0] > ourmesh->uvlim[1][0]) {
338 greg 2.1 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 greg 2.7 double marg; /* expand past endpoints */
343     marg = (2./(1L<<(8*sizeof(uint16)))) *
344     (ourmesh->uvlim[1][i] -
345 greg 2.10 ourmesh->uvlim[0][i]) + FTINY;
346 greg 2.1 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 schorsch 2.9 cvmeshoct( /* convert triangles in subtree */
356     OCTREE ot
357     )
358 greg 2.1 {
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 schorsch 2.9 cvmesh(void) /* convert mesh and octree leaf nodes */
382 greg 2.1 {
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     }